哲学家进餐问题是一个多线程运用的经典例子,涉及到线程同步/互斥,临界区访问问题以及一个避免死锁的解决方法。
在Linux下实现的具体代码如下:
有五个哲学家绕着圆桌坐,每个哲学家面前有一盘面,两人之间有一支筷子,这样每个哲学家左右各有一支筷子。哲学家有2个状态,思考或者拿起筷子吃饭。如果哲学家拿到一只筷子,不能吃饭,直到拿到2只才能吃饭,并且一次只能拿起身边的一支筷子。一旦拿起便不会放下筷子直到把饭吃完,此时才把这双筷子放回原处。如果,很不幸地,每个哲学家拿起他或她左边的筷子,那么就没有人可以吃到饭了。这就会造成死锁了。这是需要坚决杜绝的,正如操作系统的死锁问题。
编号为i的哲学家就餐的算法如下:
While(true){
If( i % 2 == 0){ //偶数号哲学家
P(左边筷子对应的信号量)
P(右边筷子对应的信号量)
拿起两只筷子吃饭
V(右边筷子对应的信号量)
V(左边筷子对应的信号量)
}else{ //奇数号哲学家
P(右边筷子对应的信号量)
P(左边筷子对应的信号量)
拿起两只筷子吃饭
V(左边筷子对应的信号量)
V(右边筷子对应的信号量)
}
吃饱后随意的睡上一段时间
}
在Linux下实现的具体代码如下:
#include <iostream>
#include <cstdio>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
#define N 6
#define LEFT i
#define RIGHT (i+1) % N
using namespace std;
class Semaphore {
private:
sem_t sem;
public:
Semaphore(int value = 1) {
sem_init(&sem,0,value); //初始化信号量,0表示信号量在线程间共享
}
void P() {
sem_wait(&sem); //等待信号,获取拥有权
}
void V() {
sem_post(&sem); //释放信号,释放拥有权
}
};
Semaphore mutex[N];
pthread_t thread[N];
int id[N];
void* solve(void* param) {
int i = *((int*)param);
while(1) {
if(i % 2 == 0) {
mutex[LEFT].P();
mutex[RIGHT].P();
printf("哲学家%d就餐\n",i+1);
mutex[RIGHT].V();
mutex[LEFT].V();
}else {
mutex[RIGHT].P();
mutex[LEFT].P();
printf("哲学家%d就餐\n",i+1);
mutex[LEFT].V();
mutex[RIGHT].V();
}
sleep(1); //线程等待
}
pthread_exit(NULL); //结束线程
}
void thread_create() { //进程创建
int tmp;
for(int i = 0; i < N; i++) {
tmp = pthread_create(&thread[i],NULL,solve,&id[i]);
if(tmp != 0) {
printf("线程%d创建失败\n",i);
}
}
}
void thread_wait() {
for(int i = 0; i < N; i++) {
pthread_join(thread[i],NULL);
printf("线程%d结束\n",i);
}
}
int main() {
for(int i = 0; i < N; i++) {
id[i] = i;
}
thread_create();
thread_wait();
return 0;
}