哲学家进餐问题
在多线程中如何避免死锁。
问题描述:有五位哲学家围绕着餐桌坐,每一位哲学家要么思考
要么等待,要么吃饭。为了吃饭,哲学家必须拿起两支筷子(分
别放于左右两端)不幸的是,筷子的数量和哲学家相等,所以每
只筷子必须由两位哲学家共享
一、使用数组来跟踪一个哲学家的的状态:吃饭,思考或是试图拿起筷子,规定一个哲学家只有在两个邻居都不再进餐时才允许转移到进餐状态。这种方法可以使系统获得最大的并行度,即最多允许两个哲学家同时进餐。
二、给每个哲学家编号,规定奇数号的哲学家先拿他的左筷子,然后再去拿他的右筷子;而偶数号的哲学家则相反。这样总可以保证至少有一个哲学家可以进餐。
一般都使用第二种方法,高效而简单。
普通解法,会死锁,不过还得等好一会。电脑速度这么快,也差不多等了五分钟以后才死锁。但是不管等多久死锁,理论上讲,死锁是早晚的事,所以还是防着点好。
- #include <windows.h>
- #include <iostream>
- #include <process.h>
- #include <cstdlib>
- #include <ctime>
- using namespace std;
- DWORD WINAPI philosopher(LPVOID lpParameter);
- void thinking(int);
- void eating(int);
- void waiting(int);
- void print(int ,const char *);
- //全局变量
- CRITICAL_SECTION crout;//这个变量用来保证输出时不会竞争
- CRITICAL_SECTION fork[5];//定义五个临界变量,代表五更筷子
- int main(int argc,char *argv[])
- {
- HANDLE hthread[5];
- int i;
- int arg[5];
- int count = 5;
- unsigned long retval;
- InitializeCriticalSection(&crout);
- //初始化临界变量
- for(i=0;i<5;i++)
- {
- InitializeCriticalSection(fork + i);
- }
- //创建五个哲学家
- for(i = 0; i<5;i++)
- {
- arg[i] = i;
- hthread[i] = CreateThread(NULL, 0, philosopher, (void*)(arg+i), 0, NULL);
- if( hthread[i] == INVALID_HANDLE_VALUE)//如果线程创建失败返回-1
- {
- cerr << "error while create thread " << i <<endl;
- cerr << "error code : "<< GetLastError() <<endl;
- }
- }
- //等待所有线程结束
- retval = WaitForMultipleObjects(5,hthread,true,INFINITE);//等待多个线程
- if(retval == WAIT_FAILED)
- {
- cerr<< "wait error,error code: "<<GetLastError()<<endl;
- }
- for(i = 0; i<5;i++)
- {
- if(CloseHandle(hthread[i]) == false)//关闭句柄
- {
- cerr << "error while close thread " <<i<<endl;
- cerr << "error code: "<<GetLastError()<<endl;
- }
- }
- return 0;
- }
- DWORD WINAPI philosopher(LPVOID lpParameter)
- {
- int n = ((int *)lpParameter)[0];
- print(n," is in!");
- //srand(time(NULL));
- while(true)
- {
- thinking(n);
- waiting(n);
- eating(n);
- }
- print(n," is out!");
- return n;
- }
- void thinking(int k)
- {
- print(k," is thinking...");
- Sleep(1);
- //Sleep((rand() %100) *5);
- }
- void eating(int k)
- {
- print(k," is eating...");
- //Sleep((rand()%100) *5);
- Sleep(1);
- LeaveCriticalSection(fork + (k+1)%5);//放下右边的筷子
- //print(k," give left");
- LeaveCriticalSection(fork + k);//放下左边的筷子
- //print(k," give right");
- }
- void waiting(int k)
- {
- print(k," is waiting...");
- Sleep(1);
- EnterCriticalSection(fork + k);//获得左边的筷子
- //print(k," take left");
- EnterCriticalSection(fork + (k + 1)%5);//获得右边的筷子
- //print(k," take right");
- }
- void print(int who,const char *str)
- {
- EnterCriticalSection(&crout);
- cout<<"process "<<who<<str<<endl;
- LeaveCriticalSection(&crout);
- }
可见,死锁的时候Process0——4都是waiting...状态
略加修改就不会产生死锁了。
- void waiting(int k)
- {
- print(k," is waiting...");
- Sleep(1);
- if ( k % 2 == 0)
- {
- EnterCriticalSection(fork + k);//获得左边的筷子
- EnterCriticalSection(fork + (k + 1)%5);//获得右边的筷子
- }
- else
- {
- EnterCriticalSection(fork + (k + 1)%5);//获得右边的筷子
- EnterCriticalSection(fork + k);//获得左边的筷子
- }
- }