当前位置: 首页 > news >正文

信号量机制解决经典同步互斥问题

生产者 / 消费者问题、读者 / 写者问题和哲学家问题是操作系统的三大经典同步互斥问题。本文将介绍这三个问题的基本特点以及如何用信号量机制进行解决。

在分析这三个问题之前,我们首先需要了解用信号量机制解决同步互斥问题的一般规律: 实现同步与互斥的P、V操作都是成对出现,但互斥问题的P、V操作出现在同一个进程中;同步问题的P、V操作出现在不同进程中。

1. 生产者 / 消费者问题

1.1 基本特点

生产者/消费者问题具体表现为:

  1. 两个进程对同一个内存资源进行操作,一个是生产者,一个是消费者。
  2. 生产者往共享内存资源填充数据,如果区域满,则等待消费者消费数据。
  3. 消费者从共享内存资源取数据,如果区域空,则等待生产者填充数据。
  4. 生产者的填充数据行为和消费者的消费数据行为不可在同一时间发生。

1.2 解决思路

首先,我分析了其中存在的同步互斥关系: 生产者-消费者之间的同步关系表现为缓冲区空,则消费者需要等待生产者往里填充数据,缓冲区满则生产者需要等待消费者消费。两者共同完成数据的转移或传送;生产者-消费者之间的互斥关系表现为生产者往缓冲区里填充数据的时候,消费者无法进行消费,需要等待生产者完成工作,反之亦然。

然后,我根据存在的互斥同步关系设置了三个信号量:由于存在互斥关系,我设置了一个互斥信号量mutex控制两者不能同时操作缓冲区;由于存在同步关系,我设置了两个信号量emptyfull分别表示缓冲区中的资源数和缓冲区中的空位置数。mutex初值为1,empty初值为0,full初值为缓冲区大小。

最后,进行对生产者和消费者的行为设计:

针对生产者,生产者生产资源,先用P(full)判断缓冲区是否有空,再用P(mutex)判断是否有人在用缓冲区,若缓冲区有空且无人用,则生产者将资源放入缓冲区。放完后,先用V(mutex)释放缓冲区的使用权,再用V(empty)将缓冲区中的资源数加1,生产者进程结束。

针对消费者,消费者先用P(empty)判断缓冲区中是否有资源,再用P(mutex)判断缓冲区是否有人用,若缓冲区有资源且无人用,则消费者从缓冲区中取资源。取完后,先用V(mutex)释放缓冲区的使用权,再用V(full)将缓冲区中的空位置数加1,消费者进程结束。

1.3 代码及运行结果

生产者 / 消费者问题的C语言代码实现如下:

/*****************************************************************问题:多个生产者,多个消费者,有限缓冲区*描述:*1.两个进程对同一个内存资源进行操作,一个是生产者,一个是消费者。*2.生产者往共享内存资源填充数据,如果区域满,则等待消费者消费数据。*3.消费者从共享内存资源取数据,如果区域空,则等待生产者填充数据。*4.生产者的填充数据行为和消费者的消费数据行为不可在同一时间发生。
****************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>#define N 5  //生产者N个,消费者N个
#define BUFFERSIZE 3  //缓冲区大小sem_t mutex;  //互斥信号量
sem_t empty;  //缓冲区中的资源数
sem_t full;   //缓冲区的空位置数void *producer(void *arg) {int i = *((int *) arg);//生产者生产资源printf("The %dth producer is producing...\n", i);sleep(3);sem_wait(&full);  //判断缓冲区是否有空sem_wait(&mutex); //判断是否有人在用缓冲区//若缓冲区有空且无人用,生产者将资源放入缓冲区printf("The %dth producer is appending...\n", i);sleep(3);sem_post(&mutex); //生产者退出缓冲区sem_post(&empty); //缓冲区的资源数增加  
}void *consumer(void *arg) {int i = *((int *) arg);sem_wait(&empty); //判断缓冲区中是否有资源sem_wait(&mutex); //判断是否有人在用缓冲区//若缓冲区中有资源且无人用,消费者从缓冲区取资源printf("The %dth consumer is taking...\n", i);sleep(3);sem_post(&mutex); //消费者退出缓冲区sem_post(&full);  //缓冲区的空位置数增加//消费者消耗资源printf("The %dth consumer is consuming...\n", i);sleep(3);
}int main() {int i;pthread_t proThread[N];pthread_t conThread[N];int proId[N];int conId[N];sem_init(&mutex, 0, 1);  //初始化互斥信号量为1sem_init(&empty, 0, 0);  //初始化缓冲区中的资源数为0sem_init(&full, 0, BUFFERSIZE);  //初始化缓冲区中的空位置等于缓冲区大小for (i = 0; i < N; i++) {proId[i] = i;conId[i] = i;pthread_create (&proThread[i], NULL, producer, &proId[i]);//创建生产者线程pthread_create (&conThread[i], NULL, consumer, &conId[i]);//创建消费者线程}for ( i = 0; i < N; i++) {pthread_join(proThread[i], NULL);//等待所有的生产者线程执行完毕再结束pthread_join(conThread[i], NULL);//等待所有的消费者线程执行完毕再结束}return 0;
}

运行结果如下图所示:
生产者/消费者问题运行结果

2. 读者 / 写者问题

2.1 基本特点

读者/写者问题具体表现为:

  1. 一个进程在读的时候,其他进程也可以读。
  2. 一个进程在读/写的时候,其他进程不能进行写/读。
  3. 一个进程在写的时候,其他进程不能写。

2.2 解决思路

首先,分析其中存在的同步互斥关系:读者-写者之间没有明显的同步关系,它们不需要合作完成某件事情;读者-写者之间的互斥关系表现为两者不能同时访问文件。

然后,根据存在的互斥关系设置信号量:由于读者-写者的互斥,我设置了一个互斥信号量wsem来控制读者和写者的互斥访问。但如果只设置了这一个信号量,读者和读者之间的互斥也出现了。因为可能会有多个读者,所以我又设置了一个变量readcount记录读者的数量。这时,readcount又需要实现多个读者对它的互斥访问,为此,我设置了一个互斥信号量xwsemx的初值均为1,readcount的初值为0,现在所有的信号量已经设置好了。

最后,进行行为设计:读者 / 写者问题有读者优先与写者优先两种解决思路。

2.2.1 读者优先

读者优先的解决思路如下:

针对读进程,首先用P(x)判断是否有人在更新readcount,若无人在改动readcount,则将readcount加1。如果加1后的readcount等于1,则说明加1前的readcount为0,此时的进程为第一个读进程。第一个读进程出现,就要用P(wsem)来限制写进程的访问。然后,用V(x)释放readcount的更新权,读者开始读。读完后,再用P(x)重新获取readcount的更新权,将读进程的数量readcount减1。如果减1后的readcount等于0,则说明所有的读进程都读完了,可以用V(wsem)释放读/写的访问权了。最后,再用V(x)释放readcount的更新权。读进程结束。

针对写进程,首先用P(wsem)获取写的访问权,不让其他读/写进程访问。然后该写进程开始写,写完再用V(wsem)释放读/写的访问权。写进程结束。

2.2.2 写者优先

写者优先与读者优先的很大不同是,如果同时有读写进程在等待,要保证在等待的写进程比在等待的读进程优先执行。为此,设置了信号量z,保证等待的写进程可以跳过它前面等待的读进程。在读者优先的信号量设置基础上,增加了互斥信号量rsem控制写进程想写时,不允许新的读进程来读。增加了整型变量writecount记录等待的写者数,因writecount是共享变量,因此还要设置新的互斥信号量y以实现进程对writecount的互斥访问。

行为设计如下:

针对读进程,首先用P(z)保证写者优先,然后用P(rsem)判断有没有写进程在临界区,有,则等待;没有,则不让新的写进程进入临界区。接下来用P(x)开始对readcount的互斥访问,更新读进程的数量,第一个读进程用P(wsem)判断是否有写进程在进行写操作,有,则需要等待;没有,则不让写进程进行新写操作,用V(x)结束对readcount的互斥访问,用V(rsem)给写进程进入临界区的权利。然后V(z),可以开始读了。读完后的行为与读者优先时一样。读进程结束。

针对写进程,首先用P(y)开始对writecount的互斥访问,更新写进程的数量,第一个写进程需要判断是否有读进程在临界区,有的话需要等待,没有的话不让新的读进程进来。然后,用V(y)结束对writecount的互斥访问。接着就是写进程的互斥写操作了,同一时刻只有一个写进程可以写,这些行为也与读者优先时一样。在写完后,用P(y)开始对writecount的互斥访问,更新写进程数量。对最后一个离开临界区的写进程,用V(rsem)给读进程可以进临界区的权利,最后用V(y)结束对writecount的互斥访问。写进程结束。

2.3 代码及运行结果

2.3.1 读者优先

读者 / 写者问题(读者优先)的C语言代码实现如下:

/***************************************************************问题:读者/写者问题,读者优先*描述:*1.一个进程在读的时候,其他进程也可以读。*2.一个进程在读/写的时候,其他进程不能进行写/读。*3.一个进程在写的时候,其他进程不能写。*4.当至少有一个读进程在读时,后来的读进程无须等待,可直接加入。
**************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>#define N 10  //读者N个,写者N个int readcount;  //记录读进程的数量
sem_t x;     //x控制readcount的互斥访问
sem_t wsem;  //wsem对写互斥控制void *reader(void *arg) {int i = *((int *) arg);sem_wait(&x);readcount++;if (readcount == 1) { //第一个读进程出现,锁住不让写sem_wait(&wsem);}sem_post(&x);printf("The %dth reader is reading...\n", i);sleep(3);sem_wait(&x);readcount--;if (readcount == 0) { //所有的读进程读完,释放写的访问sem_post(&wsem);}sem_post(&x);
}void *writer(void *arg) {int i = *((int *) arg);sem_wait(&wsem); //锁住不让其他写进程写printf("The %dth writer is writing...\n", i);sleep(3);sem_post(&wsem); //释放写的访问
}int main() {int i;pthread_t rdThread[N];pthread_t wtThread[N];int rdId[N];int wtId[N];readcount = 0;//初始化信号量sem_init(&x, 0, 1);sem_init(&wsem, 0, 1);for (i = 0; i < N; i++) {rdId[i] = i;wtId[i] = i;pthread_create (&rdThread[i], NULL, reader, &rdId[i]);//创建读者线程pthread_create (&wtThread[i], NULL, writer, &wtId[i]);//创建写者线程}for ( i = 0; i < N; i++) {pthread_join(rdThread[i], NULL);//等待所有的读者线程执行完毕再结束pthread_join(wtThread[i], NULL);//等待所有的写者线程执行完毕再结束}return 0;
}

运行结果如下图所示:
读者优先的运行结果

2.3.2 写者优先

读者 / 写者问题(写者优先)的C语言代码实现如下:

/***************************************************************问题:读者/写者问题,写者优先*描述:*1.一个进程在读的时候,其他进程也可以读。*2.一个进程在读/写的时候,其他进程不能进行写/读。*3.一个进程在写的时候,其他进程不能写。*4.写进程声明想写时,不允许新的读进程来访问数据
**************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>#define N 10  //读者N个,写者N个int readcount;  //记录读进程的数量
int writecount; //记录写进程的数量
sem_t x;     //x控制readcount的互斥访问
sem_t y;     //y控制writecount的互斥访问
sem_t z;     //z保证写跳过读,保证写优先
sem_t wsem;  //wsem对写互斥控制
sem_t rsem;  //rsem对读互斥控制void *reader(void *arg) {int i = *((int *) arg);sem_wait(&z);sem_wait(&rsem);sem_wait(&x);readcount++;if (readcount == 1) { //第一个读进程出现,锁住不让写sem_wait(&wsem);}sem_post(&x);sem_post(&rsem);  //释放读的访问,允许其他读者进入sem_post(&z);printf("The %dth reader is reading...\n", i);sleep(3);sem_wait(&x);readcount--;if (readcount == 0) { //所有的读进程读完,释放写的访问sem_post(&wsem);}sem_post(&x);
}void *writer(void *arg) {int i = *((int *) arg);sem_wait(&y);writecount++;if(writecount == 1) { //第一个写进程,判断是否有读进程正在进行sem_wait(&rsem);}sem_post(&y);sem_wait(&wsem); //锁住不让其他写进程写printf("The %dth writer is writing...\n", i);sleep(3);sem_post(&wsem); //释放写的访问sem_wait(&y);writecount--;if (writecount == 0) { //所有写进程写完,释放读的访问sem_post(&rsem);}sem_post(&y);
}int main() {int i;pthread_t rdThread[N];pthread_t wtThread[N];int rdId[N];int wtId[N];readcount = 0;writecount = 0;//初始化信号量sem_init(&x, 0, 1);sem_init(&y, 0, 1);  sem_init(&z, 0, 1);  sem_init(&wsem, 0, 1);sem_init(&rsem, 0, 1);for (i = 0; i < N; i++) {rdId[i] = i;wtId[i] = i;pthread_create (&rdThread[i], NULL, reader, &rdId[i]);//创建读者线程pthread_create (&wtThread[i], NULL, writer, &wtId[i]);//创建写者线程}for ( i = 0; i < N; i++) {pthread_join(rdThread[i], NULL);//等待所有的读者线程执行完毕再结束pthread_join(wtThread[i], NULL);//等待所有的写者线程执行完毕再结束}return 0;
}

运行结果如下图所示:
写者优先的运行结果

3. 哲学家问题

3.1 基本特点

哲学家问题的具体表现为:
有N个哲学家,他们的生活方式是交替地进行思考和进餐,哲学家们共用一张圆桌,分别坐在周围的N张椅子上,在圆桌上有N个碗和N支筷子,平时哲学家进行思考,饥饿时便试图取其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐,进餐完毕,放下筷子又继续思考。

约束条件如下:

  1. 只有拿到两只筷子时,哲学家才能吃饭。
  2. 如果筷子已被别人拿走,则必须等别人吃完之后才能拿到筷子。
  3. 任一哲学家在自己未拿到两只筷子吃饭前,不会放下手中拿到的筷子。
  4. 用完之后将筷子返回原处。

3.2 解决思路

首先,分析其中存在的同步互斥关系:筷子是临界资源,每根筷子只能一个人取,这是互斥关系;如果筷子被取走,那么需要等待,这是同步关系。

可能出现死锁的错误解法是:设置一个信号量表示一只筷子,有N只筷子,所以设置N个信号量,哲学家每次饥饿时先试图拿左边的筷子,再试图拿右边的筷子,拿不到则等待,拿到了就吃饭,最后逐个放下筷子。这种解法下,如果N个哲学家同时感到饥饿,同时试图拿左边的筷子,都没成功;又同时试图拿右边的筷子,又都没成功,由于第3个约束条件的存在,这时出现了死锁。

因此,此问题的关键是互斥及避免死锁。在错误解法的基础上,一种可行解法是让奇数号与偶数号的哲学家拿筷子的顺序不同,破坏环路等待条件。

第二种可行的解法是只允许N-1位哲学家同时进餐,这样N-1个人都拿起一根筷子时,第N个人不能再拿筷子,就空出了一根筷子。

3.3 代码及运行结果

3.3.1 方法1

编号为奇数的哲学家先拿左手的筷子,编号为偶数的哲学家先拿右手的筷子,C语言代码实现如下:

/************************************************************************问题:哲学家问题*描述:*五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,*在桌子上有五个碗和五根筷子,他们的状态是思考和进餐交替,*平时,一个哲学家思考,饿了就取离他最近的筷子,只有拿到了两只筷子才能进餐。*进餐毕,放下筷子继续思考。*方法1:编号为奇数的哲学家先拿左手的筷子,编号为偶数的哲学家先拿右手的筷子
***********************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>#define N 5/*一共N根筷子,每根筷子设置一个信号量,记录筷子的状态*/
sem_t chopsticks[N]; //1代表筷子已经被用过,0代表筷子正等待被使用void *philosopher(void *arg) {int i = *((int *) arg);//为避免死锁,编号为奇数的哲学家先拿左手的筷子,编号为偶数的哲学家先拿右手的筷子if (i % 2) { //奇数编号sem_wait(&chopsticks[i]);  //先拿左手的筷子sleep(1);sem_wait(&chopsticks[(i + 1) % N]);  //再拿右手的筷子//哲学家吃啊吃printf("The %dth philosopher is eating...\n", i);sleep(3); sem_post(&chopsticks[(i + 1) % N]);sleep(1);sem_post(&chopsticks[i]);//哲学家想啊想printf("The %dth philosopher is thinking...\n", i);sleep(3);  }else {sem_wait(&chopsticks[(i + 1) % N]);  //先拿右手的筷子sleep(1);sem_wait(&chopsticks[i]);  //再拿左手的筷子//哲学家吃啊吃printf("The %dth philosopher is eating...\n", i);sleep(3); sem_post(&chopsticks[i]);sleep(1);sem_post(&chopsticks[(i + 1) % N]);//哲学家想啊想printf("The %dth philosopher is thinking...\n", i);sleep(3);  }
}int main() {int i;pthread_t thread[N];int id[N];  //记录哲学家编号for (i = 0; i < N; i++) { //初始化信号量为1sem_init(&chopsticks[i], 0, 1);}for (i = 0; i < N; i++) {id[i] = i;pthread_create (&thread[i], NULL, philosopher, &id[i]);//创建线程}for ( i = 0; i < N; i++) {pthread_join(thread[i], NULL);//等待所有的线程执行完毕再结束}return 0;
}

运行结果如下图所示:
哲学家问题方法1运行结果

3.3.2 方法2

只允许N-1位哲学家同时进入餐厅,C语言代码实现如下:

/************************************************************************问题:哲学家问题*描述:*五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,*在桌子上有五个碗和五根筷子,他们的状态是思考和进餐交替,*平时,一个哲学家思考,饿了就取离他最近的筷子,只有拿到了两只筷子才能进餐。*进餐毕,放下筷子继续思考。*方法2:只允许4位哲学家同时进入餐厅
***********************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>#define N 5/*一共N根筷子,每根筷子设置一个信号量,记录筷子的状态*/
sem_t chopsticks[N]; //1代表筷子已经被用过,0代表筷子正等待被使用
sem_t room;void *philosopher(void *arg) {int i = *((int *) arg);sem_wait(&room);sleep(1);sem_wait(&chopsticks[i]);  //先拿左手的筷子sleep(1);sem_wait(&chopsticks[(i + 1) % N]);  //再拿右手的筷子//哲学家吃啊吃printf("The %dth philosopher is eating...\n", i);sleep(3); sem_post(&chopsticks[(i + 1) % N]);sleep(1);sem_post(&chopsticks[i]);sleep(1);sem_post(&room);//哲学家想啊想printf("The %dth philosopher is thinking...\n", i);sleep(3);  
}int main() {int i;pthread_t thread[N];int id[N];  //记录哲学家编号for (i = 0; i < N; i++) { //初始化筷子信号量为1sem_init(&chopsticks[i], 0, 1);}sem_init(&room, 0, 4);   //初始化room信号量为4for (i = 0; i < N; i++) {id[i] = i;pthread_create (&thread[i], NULL, philosopher, &id[i]);//创建线程}for ( i = 0; i < N; i++) {pthread_join(thread[i], NULL);//等待所有的线程执行完毕再结束}return 0;
}

运行结果如下图所示:
哲学家问题方法2运行结果

相关文章:

信号量机制解决经典同步互斥问题

生产者 / 消费者问题、读者 / 写者问题和哲学家问题是操作系统的三大经典同步互斥问题。本文将介绍这三个问题的基本特点以及如何用信号量机制进行解决。 在分析这三个问题之前&#xff0c;我们首先需要了解用信号量机制解决同步互斥问题的一般规律&#xff1a; 实现同步与互斥…...

java基础09-==和equals()的区别,附代码举例

和equals()的区别 在Java中&#xff0c;和equals()是两个不同的运算符&#xff0c;它们在比较对象时有着本质的区别。 运算符: 用于比较两个基本数据类型&#xff08;如int、char等&#xff09;或两个对象的引用。 当用于比较基本数据类型时&#xff0c;它会比较它们的值。 当…...

qml与C++的交互

qml端使用C对象类型、qml端调用C函数/c端调用qml端函数、qml端发信号-连接C端槽函数、C端发信号-连接qml端函数等。 代码资源下载&#xff1a; https://download.csdn.net/download/TianYanRen111/88779433 若无法下载&#xff0c;直接拷贝以下代码测试即可。 main.cpp #incl…...

LabVIEW电路板插件焊点自动检测系统

LabVIEW电路板插件焊点自动检测系统 介绍了电路板插件焊点的自动检测装置设计。项目的核心是使用LabVIEW软件&#xff0c;开发出一个能够自动检测电路板上桥接、虚焊、漏焊和多锡等焊点缺陷的系统。 系统包括成像单元、机械传动单元和软件处理单元。首先&#xff0c;利用工业相…...

第十一站:多态练习ODU

实现动态切换 ODU.h #pragma once #include <iostream> using namespace std; #define ODU_TYPE_311_FLAG "311" #define ODU_TYPE_335_FLAG "335" enum class ODU_TYPE {ODU_TYPE_311,ODU_TYPE_335,ODU_TYPE_UNKNOW };class ODU{ public:ODU();//发…...

【深度学习】详解利用Matlab和Python中 LSTM 网络实现序列分类

🔗 运行环境:Matlab、Python 🚩 撰写作者:左手の明天 🥇 精选专栏:《python》 🔥 推荐专栏:《算法研究》 🔐#### 防伪水印——左手の明天 ####🔐 💗 大家好🤗🤗🤗,我是左手の明天!好久不见💗 💗今天分享Matlab深度学习—— LSTM 网络实现序列分...

Unity 工厂方法模式(实例详解)

文章目录 在Unity中&#xff0c;工厂方法模式是一种创建对象的常用设计模式&#xff0c;它提供了一个接口用于创建对象&#xff0c;而具体的产品类是由子类决定的。这样可以将对象的创建过程与使用过程解耦&#xff0c;使得代码更加灵活和可扩展。 工厂模式的主要优点如下&…...

2024年美赛数学建模思路 - 案例:异常检测

文章目录 赛题思路一、简介 -- 关于异常检测异常检测监督学习 二、异常检测算法2. 箱线图分析3. 基于距离/密度4. 基于划分思想 建模资料 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 一、简介 – 关于异常…...

一键完成,批量转换HTML为PDF格式的方法,提升办公效率

在当今数字化的时代&#xff0c;HTML和PDF已经成为两种最常用的文件格式。HTML用于网页内容的展示&#xff0c;而PDF则以其高度的可读性和不依赖于平台的特性&#xff0c;成为文档分享和传播的首选格式。然而&#xff0c;在办公环境中&#xff0c;我们经常需要在这两种格式之间…...

【重点问题】攻击面发现及管理

Q1&#xff1a;在使用长亭云图极速版时&#xff0c;是否需要增设白名单扫描节点&#xff1f; 长亭云图极速版高级网络安全产品基于一种理念&#xff0c;即攻击面发现是一个不断变换且需要持续对抗的过程。在理想的情况下&#xff0c;用户应当在所有预置防护设施发挥作用的环境…...

UE4外包团队:国外使用UE4虚幻引擎制作的十个知名游戏

​ 1.俄罗斯方块效果&#xff08;任天堂 Switch、PlayStation 4、PC、Xbox&#xff09; 2.耀西的手工世界&#xff08;任天堂 Switch&#xff09; 3. Final Fantasy 7 Remake Intergrade (PlayStation, PC) 4.《堡垒之夜》&#xff08;PC、Nintendo Switch、PlayStation、Xb…...

解决springboot+mybatisplus返回时间格式带T

原因&#xff1a;我service实现类的代码是 Overridepublic Map<String, Object> queryDictPage(Map<String, Object> queryMap) {Map<String,Object> map new HashMap<>();QueryWrapper<Dict> wrapper new QueryWrapper<>(); // …...

纯命令行在Ubuntu中安装qemu的ubuntu虚拟机,成功备忘

信息总体还算完整&#xff0c;有个别软件更新了名字&#xff0c;所以在这备忘一下 1. 验证kvm是否支持 ________________________________________________________________ $ grep vmx /proc/cpuinfo __________________________________________________________________…...

Vue的学习Day1_是什么以及两种风格

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Vue是什么&#xff1f;二、渐进式框架1.渐进式 三、Vue API风格1.选项式 API (Options API)2.组合式 API (Composition API) 四、Vue 开发前的准备 前言 放…...

磁悬浮人工心脏的不良事件分析:美国FDA数据库的启示

引言&#xff1a; 左心室辅助装置&#xff08;LVAD&#xff09;是治疗末期难治性心力衰竭&#xff08;HF&#xff09;患者的有效手段。磁悬浮人工心脏HeartMate-3&#xff08;磁悬浮人工心脏&#xff09;作为第三代LVAD&#xff0c;自2017年获得美国食品药品监督管理局&#x…...

HarmonyOS(十二)——全面认识HarmonyOS三种渲染控制

渲染控制概述 ArkUI通过自定义组件的build()函数和builder装饰器中的声明式UI描述语句构建相应的UI。在声明式描述语句中开发者除了使用系统组件外&#xff0c;还可以使用渲染控制语句来辅助UI的构建&#xff0c;这些渲染控制语句包括控制组件是否显示的条件渲染语句&#xff…...

SQL 系列教程(二)

目录 SQL DELETE 语句 DELETE 语句 演示数据库 DELETE 实例 删除所有行 SQL TOP, LIMIT, ROWNUM 子句 TOP 子句 演示数据库 SQL TOP、LIMIT 和 ROWNUM 示例 SQL TOP PERCENT 实例 添加WHERE子句 SQL MIN() 和 MAX() 函数 MIN() 和 MAX() 函数 演示数据库 MIN() …...

CSS实现文本和图片无限滚动动画

Demo图如下&#xff1a; <style>* {margin: 0;padding: 0;box-sizing: border-box;font-family: Poppins, sans-serif;}body {min-height: 100vh;background-color: rgb(11, 11, 11);color: #fff;display: flex;flex-direction: column;justify-content: center;align-i…...

MacOS 无法ping 通 github.com 解决方案

ping github.com 会显示请求超时&#xff1a; PING github.com (192.30.253.112): 56 data bytes Request timeout for icmp_seq 0 Request timeout for icmp_seq 1 Request timeout for icmp_seq 2 Request timeout for icmp_seq 3 Request timeout for icmp_seq 4 Request …...

Mac 也能玩文明6!下载安装详细教程

最近朋友给我分享了一个 Mac 玩文明6的方法&#xff0c;丝毫不卡顿&#xff0c;非常流畅&#xff0c;分享给大家 文明6是最新的文明系列游戏&#xff0c;和以往的文明游戏一样&#xff0c;玩家将从石器时代创建文明&#xff0c;然后迈向信息时代&#xff0c;最终通过军事、经济…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...