哲学家就餐问题是一个了解和练习线程间同步的非常好的小例子,题为 5 个哲学家(线程)围成一桌就餐,但是只有 5 只筷子(锁),一个人想要吃饭就必须要拥有左侧的筷子(锁1)和右侧的筷子(锁2)才能吃饭。每一个哲学家刚进桌前都持有了自己左侧的筷子,这样所有人只有一只筷子都无法就餐,所以就要想办法去拿右侧的筷子,而因为右侧的筷子被别人持有,所以无法拿到,这个时间就成了死锁状态。所以必须要有一个解锁的条件,那就是在哲学家尝试去拿右侧筷子的时候,如果失败了,那么将自己左手边的筷子放下,此时这个哲学家左侧人就可以持有他原来左手边的筷子来就餐了。实现的具体步骤和代码如下:


【代码实现】

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

#define THREAD_COUNT 5
pthread_mutex_t mutex[THREAD_COUNT];

// 用以给线程传递数据用的结构体
struct tag_thread_arg
{
int pthread_idx;// 线程的编号,对应哲学家编号
pthread_mutex_t left;// 左侧筷子
pthread_mutex_t right;// 右侧筷子
};

void* pthreadFunc(void* arg)
{
// 得到传递进来的结构体
struct tag_thread_arg* local =
(struct tag_thread_arg*)arg;

while (1)
{
// 左侧筷子锁,循环拿左侧的锁,拿到以后再向下走
while (pthread_mutex_trylock(&local->left) != 0);
// 判断右侧筷子是否可以锁定
if (pthread_mutex_trylock(&local->right) == 0)
{
// 可以锁定则吃饭
int sec = rand() % 5 + 1;
sleep(sec);
printf(“thread %d mixi %ds\n”, local->pthread_idx, sec);
// 吃完把两把锁都释放
pthread_mutex_unlock(&local->right);
pthread_mutex_unlock(&local->left);
}
else
{
// 如果不能锁定右侧筷子,则把自己左侧筷子放开,让别人先吃
pthread_mutex_unlock(&local->left);
}
}
return (void*)0;
}

int main(int argc, char* argv[])
{
srand(time(NULL));
pthread_t pid[5];
int i;

// 初始化5个互斥量
for (i = 0; i < THREAD_COUNT; i++)
{
pthread_mutex_init(&mutex[i], NULL);
}

// 定义5个结构体用来给线程传递数据
struct tag_thread_arg arg[5];
// 创建5个线程,并把结构体内容初始化后传递进去
for (i = 0; i < THREAD_COUNT; i++)
{
arg[i].pthread_idx = i;//线程ID,对应哲学家编号
arg[i].left = mutex[i];//锁1,对应哲学家左侧筷子
arg[i].right = mutex[(i + 1) % THREAD_COUNT];//锁2,对应哲学家右侧筷子
pthread_create(&pid[i], NULL, pthreadFunc, (void*)&arg[i]);// 创建线程
}

// 等待所有线程结束
for (i = 0; i < 5; i++)
{
pthread_join(pid[i], NULL);
}

// 回收互斥量资源
for (i = 0; i < THREAD_COUNT; i++)
{
pthread_mutex_destroy(&mutex[i]);
}

return 0;
}

程序运行后结果如下图,每个哲学家都可以正常的就餐了: 2015-07-05_173820