linux多线程【3】哲学家用餐-mutex实现

ref:

http://blog.csdn.net/kongzhp/article/details/7487150



    5跟筷子,5个哲学家,哲学家要吃饭,自然要两根筷子,这样就出现资源争用的情况。哲学家只能用左边和右边的筷子,两根筷子备齐才能吃饭!


    使用mutex的话,就是每个筷子一个mutex,需要5个mutex,哲学家先lock左边的筷子,如果有人已经在用那根筷子了,那就等着,不然左边的筷子就拿到手了,然后去拿右边的筷子,如果拿到了,那就开饭!如果拿不到,那就等一下再尝试,尝试累计10次的话,干脆放弃,把左边的筷子也放回去让别人先吃了再说!

    如何检测是否真的lock成功了呢?那就是给筷子赋值,把自己的编号赋值给两根筷子,然后usleep一下,这个时候很可能线程调度,cpu把机会给了别的线程,假如没有lock住,那么可能筷子的值会发生意外的修改。假如一直没有被错误的修改,那么应该就已经lock 成功了咯!

    在没有使用同步时,会发生很多意外修改的情况:

#include <pthread.h>
#include <stdio.h>
//#include<process.h>
#include<errno.h>
#define N 5
#define M 10

int cholk[N];
pthread_mutex_t mt[N];


void *func(void *);

int main()
{
	pthread_t person[N];
	int i;

	//init thread
	for(i=0;i<N;i++)
	{
		pthread_mutex_init(mt+i,NULL);
	}

	// create N threads
	for(i=0;i<N; i++)
	{
		if(pthread_create(person+i, NULL, func, (void*)i)!=0 )
		{
			fprintf(stderr, "create error\n");
			exit(2);
		}
	}

	//wait for thread terminal
	for(i=0;i<N;i++)
	{
		pthread_join(*(person+i), NULL);
	}
	return 0;
}

void *func(void *p)
{


	while(1)
	{
		int i=(int)p;
		int j=M;

	/*	while(0 != pthread_mutex_trylock(mt+i) )
		{
			usleep(rand()%20);
		} // lock the left one!
		//pthread_mutex_lock(mt+i);
		while(j)
		{
			if(0==pthread_mutex_trylock(mt +(i+1)%N  ) )  // try to lock the right one, terminal after M times fails
				break;
			j--;
		}

		if(j==0) // fail,release the left one
		{
			pthread_mutex_unlock(mt+i);
			continue;
		}*/

		cholk[i]=i;
		cholk[(i+1)%N]=i;
		usleep(100); 
		printf("The %d th person have dinner! %d,%d  %s\n", i, cholk[i], cholk[(i+1)%N],
                     (cholk[i]==cholk[(i+1)%N] && cholk[i]==i) ? "right":"wrong" );

		// after eat dinner, release both;
		//pthread_mutex_unlock(mt+i);
		//pthread_mutex_unlock(mt+(i+1)%N);
		usleep(10);
	}
		return NULL;


}




同步以后:

#include <pthread.h>
#include <stdio.h>
//#include<process.h>
#include<errno.h>
#define N 5
#define M 10

int cholk[N];
pthread_mutex_t mt[N];


void *func(void *);

int main()
{
	pthread_t person[N];
	int i;

	//init thread
	for(i=0;i<N;i++)
	{
		pthread_mutex_init(mt+i,NULL);
	}

	// create N threads
	for(i=0;i<N; i++)
	{
		if(pthread_create(person+i, NULL, func, (void*)i)!=0 )
		{
			fprintf(stderr, "create error\n");
			exit(2);
		}
	}

	//wait for thread terminal
	for(i=0;i<N;i++)
	{
		pthread_join(*(person+i), NULL);
	}
	return 0;
}

void *func(void *p)
{


	while(1)
	{
		int i=(int)p;
		int j=M;

		while(0 != pthread_mutex_trylock(mt+i) )
		{
			usleep(rand()%20);
		} // lock the left one!
		//pthread_mutex_lock(mt+i);
		while(j)
		{
			if(0==pthread_mutex_trylock(mt +(i+1)%N  ) )  // try to lock the right one, terminal after M times fails
				break;
			j--;
		}

		if(j==0) // fail,release the left one
		{
			pthread_mutex_unlock(mt+i);
			continue;
		}

		cholk[i]=i;
		cholk[(i+1)%N]=i;
		usleep(100); 
		printf("The %d th person have dinner! %d,%d  %s\n", i, cholk[i], cholk[(i+1)%N],
                     (cholk[i]==cholk[(i+1)%N] && cholk[i]==i) ? "right":"wrong" );

		// after eat dinner, release both;
		pthread_mutex_unlock(mt+i);
		pthread_mutex_unlock(mt+(i+1)%N);
		usleep(10);
	}
		return NULL;


}

    效果:



注意:

1.lock第一个筷子的时候,最好用pthread_mutex_lock,用try_lock的话应该用while循环加延时,但是这样的话try_lock就会反复去轮询,导致效率降低,而pthread_mutex_lock则会一直阻塞,就这么等着,不占用cpu时间。用try_lock,while循环,中间加入延时,效率有所改善,不然好多时间都消耗在轮询里。可见,多线程不仅要编的对,还要编的高效,需要对同步机制有细致的了解。

2.另外,有几次测试的时候,发现只有1和3交替吃饭,别人都没得吃!可能是其他两个usleep没有加入,所以呢,线程切换的时候,大部分都是在临界区里被切换出去,那么其他线程锁不住,最后还是切换回来,导致有的线程一直抢不到啊。

下图是0和2有饭吃,别的没得吃,这个是把所有usleep都注释掉的结果。


unlock以后usleep一下,就不会发生这种情况了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值