哲学家就餐问题

时间:2021-09-26 00:11:15
/*每个哲学家相当于一个线程*/
/**
* 哲学家就餐问题是1965年由Dijkstra提出的一种线程同步的问题<p>
*
* <b>问题描述:</b>
*
* 一圆桌前坐着N位哲学家,两个人中间有一只筷子,桌子*有面条。哲学家思考问题,
* 当饿了的时候拿起左右两只筷子吃饭,必须拿到两只筷子才能吃饭。上述问题会产生死锁的情况,
* 当5个哲学家都拿起自己右手边的筷子,准备拿左手边的筷子时产生死锁现象。<p>
*
* <b>解决办法:</b><br>
*
* 1、添加一个服务生,只有当经过服务生同意之后才能拿筷子,服务生负责避免死锁发生。<br>
*
* 2、每个哲学家必须确定自己左右手的筷子都可用的时候,才能同时拿起两只筷子进餐,
* 吃完之后同时放下两只筷子。<br>
*
* 3、规定每个哲学家拿筷子时必须拿序号小的那只,这样最后一位未拿到筷子的哲学家只剩下
* 序号大的那只筷子,不能拿起,剩下的这只筷子就可以被其他哲学家使用,避免了死锁。
* 这种情况不能很好的利用资源。<br>
*/
class Philosopher extends Thread {
private String name;
private Fork fork;

public Philosopher(String name, Fork fork) {
super(name);
this.name = name;
this.fork = fork;
}

public void run() {
while (true) {
thinking();
fork.takeForks();
eating();
fork.putForks();
}
}

public void eating() {
System.out.println("Philosopher " + name + " : I am Eating:" + name);
try {
sleep(1000);// 模拟吃饭,占用一段时间资源
} catch (InterruptedException e) {
e.printStackTrace();
}
}

public void thinking() {
System.out.println("Philosopher " + name + " : I am Thinking:" + name);
try {
sleep(1000);// 模拟思考
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

class Fork {
    /* N只筷子,初始为都未被用 */
    private boolean[] used = new boolean[Constants.N];

    /* 只有当左右手的筷子都未被使用时,才允许获取筷子,且必须同时获取左右手筷子 */
    public synchronized void takeForks() {
        String name = Thread.currentThread().getName();
        int i = Integer.parseInt(name);
        while (used[i] || used[(i + Constants.N - 1) % Constants.N]) {
            try {
                wait();// 如果左右手有一只正被使用,等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        used[i] = true;
        used[(i + Constants.N - 1) % Constants.N] = true;
    }

    /* 必须同时释放左右手的筷子 */
    public synchronized void putForks() {
        String name = Thread.currentThread().getName();
        int i = Integer.parseInt(name);

        used[i] = false;
        used[(i + Constants.N - 1) % Constants.N] = false;
        notifyAll();// 唤醒其他线程
    }
}

interface Constants {
public static final int N = 5;
}

// 测试
public class PhilosopherTest {
public static void main(String[] args) {
Fork fork = new Fork();

for (int i = 0; i < Constants.N; i++)
new Philosopher(Integer.toString(i), fork).start();
}
}
#include<stdio.h>#include<pthread.h>#include<semaphore.h>#define N5#define LEFT(i + N - 1) % N#define RIGHT(i + 1) % N#define THINKING0#define EATING1static intstate[N];static pthread_mutex_tmutex;static void take_forks(int);static void put_forks(int);static void testPhilosopher(int); static void eat(int);static void think(int);static void *philosopher(void*);static void *philosopher(void* arg) {while ( 1 ) {think((int)arg);take_forks((int)arg);eat((int)arg);put_forks((int)arg);}}static void eat(int i) {if (state[i] == EATING) {printf("Philosopher %d is eating............\n", i);sleep(2);}}static void think(int i) {if (state[i] == THINKING) {printf("Philosopher %d is thinking...\n", i);sleep(2);}}static voidtake_forks(int i) {pthread_mutex_lock(&mutex);testPhilosopher(i);pthread_mutex_unlock(&mutex);}static voidput_forks(int i) {pthread_mutex_lock(&mutex);state[i] = THINKING;pthread_mutex_unlock(&mutex);}static void testPhilosopher(int i) {if (state[LEFT] != EATING && state[RIGHT] != EATING) {state[i] = EATING;}}intmain() {  //gcc -std=c99 philosopher.c -o thread1 -lpthreadint res;pthread_t a_thread[N];void *thread_result;res = pthread_mutex_init(&mutex, NULL);if (res != 0) {perror("Mutex initialization failed.");exit(-1);}for (int i = 0; i < N; i++)res = pthread_create(&a_thread[i], NULL, philosopher, (void*)i);if (res != 0) {perror("Thread creation failed.");exit(-1);}printf("hello\n");for (int i = 0; i < N; i++)res = pthread_join(a_thread[i], &thread_result);if (res != 0) {perror("Thread join failed.");exit(-1);}printf("world\n");}

#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>

#define N5
#define LEFT((i + N - 1) % N)
#define RIGHT(i % N)
#define THINKING0
#define EATING1

static intstate[N];
static pthread_mutex_tmutex;
static pthread_cond_tcond;

static void take_forks(int);
static void put_forks(int);
static void testPhilosopher(int);
static void eat(int);
static void think(int);
static void *philosopher(void*);

static void
eat(int i) {
printf("Philosopher %d is eating............\n", i);
sleep(2);
}

static void
think(int i) {
printf("Philosopher %d is thinking...\n", i);
sleep(2);
}

static void
*philosopher(void* arg) {
while ( 1 ) {
think((int)arg);
take_forks((int)arg);
eat((int)arg);
put_forks((int)arg);
}
}

static void
take_forks(int i) {
pthread_mutex_lock(&mutex);
//printf("before testPhilosopher %d.....\n", i);
testPhilosopher(i);
//printf("after testPhilosopher %d.....\n", i);
pthread_mutex_unlock(&mutex);
}

static void
put_forks(int i) {
pthread_mutex_lock(&mutex);
state[LEFT] = THINKING;
state[RIGHT] = THINKING;
pthread_cond_signal(&cond);
printf("putforks %d, after signal....\n", i);
pthread_mutex_unlock(&mutex);
}

static void testPhilosopher(int i) {
while (state[LEFT] == EATING || state[RIGHT] == EATING) {
//printf("test %d, before condition...., left = %d, right = %d \n", i, LEFT, RIGHT);
pthread_cond_wait(&cond, &mutex);
//printf("test %d, after condition...., left = %d, right = %d \n", i, LEFT, RIGHT);
}
state[LEFT] = EATING;
state[RIGHT] = EATING;
}

int
main() {
int res;
pthread_t a_thread[N];
void *thread_result;

res = pthread_mutex_init(&mutex, NULL);
if (res != 0) {
perror("Mutex initialization failed.");
exit(-1);
}

res = pthread_cond_init(&cond, NULL);
if (res != 0) {
perror("Condition initialization failed.");
exit(-1);
}

for (int i = 0; i < N; i++)
res = pthread_create(&a_thread[i], NULL, philosopher, (void*)i);

if (res != 0) {
perror("Thread creation failed.");
exit(-1);
}

printf("hello\n");
for (int i = 0; i < N; i++)
res = pthread_join(a_thread[i], &thread_result);

if (res != 0) {
perror("Thread join failed.");
exit(-1);
}

printf("world\n");
}

pthread_cond_wait()用法分析 http://blog.csdn.net/hairetz/article/details/4535920

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

static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

struct node {
intn_number;
struct node*n_next;
} *head = NULL;

/*[thread_func]*/
static void
cleanup_handler(void *arg)
{
printf("Cleanup handler of second thread.\n");
free(arg);
(void)pthread_mutex_unlock(&mtx);
}

static void
*thread_func(void *arg)
{
struct node *p = NULL;

pthread_cleanup_push(cleanup_handler, p);

while ( 1 ) {
//这个mutex主要是用来保证pthread_cond_wait的并发性
pthread_mutex_lock(&mtx);

/*这个while要特别说明一下,单个pthread_cond_wait功能很完善,
* 为何这里要有一个while (head == NULL)呢?因为pthread_cond_wait
* 里的线程可能会被意外唤醒,如果这个时候head != NULL,
* 则不是我们想要的情况。这个时候,应该让线程继续进入pthread_cond_wait
*/
while (head == NULL) {
/* pthread_cond_wait会先解除之前的pthread_mutex_lock锁定的mtx,
* 然后阻塞在等待对列里休眠,直到再次被唤醒(大多数情况下是等
* 待的条件成立而被唤醒,唤醒后,该进程会先锁定先pthread_mutex_lock(&mtx);,
* 再读取资源
*/
pthread_cond_wait(&cond, &mtx);
//用这个流程是比较清楚的/*block-->unlock-->wait() return-->lock*/
}

p = head;
head = head -> n_next;

printf("Got %d from front of queue.\n", p -> n_number);

free(p);
//临界区数据操作完毕,释放互斥锁
pthread_mutex_unlock(&mtx);
}
pthread_cleanup_pop(0);
return 0;
}

int
main(void)
{
pthread_ttid;
inti;
struct node*p;

/*子线程会一直等待资源,类似生产者和消费者,但是这里的消费者可以是多个消费者,
* 而不仅仅支持普通的单个消费者,这个模型虽然简单,但是很强大
*/
pthread_create(&tid, NULL, thread_func, NULL);

/*[tx6-main]*/
for (i = 0; i < 10; i++) {
p = malloc(sizeof(struct node));
p->n_number = i;

//需要操作head这个临界资源,先加锁,
pthread_mutex_lock(&mtx);
p -> n_next = head;
head = p;
pthread_cond_signal(&cond);
//解锁
pthread_mutex_unlock(&mtx);

sleep(1);
}

printf("thread 1 wanna end the line.So cancel thread 2.\n");

/*关于pthread_cancel,有一点额外的说明,它是从外部终止子线程,
* 子线程会在最近的取消点,退出线程,而在我们的代码里,最近
* 的取消点肯定就是pthread_cond_wait()了。关于取消点的信息,
* 有兴趣可以google,这里不多说了
*/
pthread_cancel(tid);
pthread_join(tid, NULL);

printf("All done -- exiting\n");

return 0;
}