首页 > 编程语言 > 详细

Linux系统开发9 线程同步

时间:2016-08-17 23:23:29      阅读:352      评论:0      收藏:0      [点我收藏+]

本文谢绝转载原文来自http://990487026.blog.51cto.com


《大纲》
Linux系统编程8 线程同步
	多线程共享资源,不加锁,同步互斥演示
	多线程共享资源,加锁,同步互斥演示
	读写锁:3个写线程,5个读线程,不加锁,并行处理
	读写锁:3个写线程,5个读线程,加读写锁,串行处理
	条件变量:生产消费者模型
	信号量
	进程间锁
	文件锁:
	习题 死锁,哲学家就餐	
	



多线程共享资源,不加锁,同步互斥演示

chunli@ubuntu:~/linux_c/thread$ cat pthread_1.c 
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NLOOP 5000
//全局变量
int counter; /* incremented by threads */
pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;


void *doit(void *vptr)
{
	int i, val;
	for (i = 0; i < NLOOP; i++) 
	{
		val = counter;
		printf("%zd: %d\n", (size_t)pthread_self(), val + 1);
		counter = val + 1;
	}
	return NULL;
}

int main(int argc, char **argv)
{
	pthread_t tidA, tidB;
	pthread_create(&tidA, NULL, doit, NULL);
	pthread_create(&tidB, NULL, doit, NULL);
	/* wait for both threads to terminate */
	pthread_join(tidA, NULL);
	pthread_join(tidB, NULL);
	return 0;
}
chunli@ubuntu:~/linux_c/thread$ 

可以看得出来,全局变量并没有被期望成5000*2

chunli@ubuntu:~/linux_c/thread$ gcc pthread_1.c -lpthread && ./a.out | tail
140320634492672: 5223
140320634492672: 5224
140320634492672: 5225
140320634492672: 5226
140320634492672: 5227
140320634492672: 5228
140320634492672: 5229
140320634492672: 5230
140320634492672: 5231
140320634492672: 5232
chunli@ubuntu:~/linux_c/thread$ gcc pthread_1.c -lpthread && ./a.out | tail
140300621051648: 4991
140300621051648: 4992
140300621051648: 4993
140300621051648: 4994
140300621051648: 4995
140300621051648: 4996
140300621051648: 4997
140300621051648: 4998
140300621051648: 4999
140300621051648: 5000
chunli@ubuntu:~/linux_c/thread$ gcc pthread_1.c -lpthread && ./a.out | tail
140619176314624: 8206
140619176314624: 8207
140619176314624: 8208
140619176314624: 8209
140619176314624: 8210
140619176314624: 8211
140619176314624: 8212
140619176314624: 8213
140619176314624: 8214
140619176314624: 8215
chunli@ubuntu:~/linux_c/thread$


多线程共享资源,加锁,同步互斥演示

chunli@ubuntu:~/linux_c/thread$ cat pthread_1.c 
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NLOOP 5000
//全局变量
int counter; /* incremented by threads */
//全局定义一把锁,静态初始化
pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;


void *doit(void *vptr)
{
	int i, val;
	for (i = 0; i < NLOOP; i++) 
	{
		//加锁只是一种机制,不加锁照样可以读写全局资源,遵循这种机制,才能保护全局资源,不遵循加锁,全局资源不被保护
		//谁拿全局资源谁拿锁
		pthread_mutex_lock(&counter_mutex);
		val = counter;
		printf("%zd: %d\n", (size_t)pthread_self(), val + 1);
		counter = val + 1;
		//释放锁
		pthread_mutex_unlock(&counter_mutex);
	}
	return NULL;
}

int main(int argc, char **argv)
{
	//锁可以在函数内定义,可以动态初始化
	//pthread_mutex_t mutex;
	//pthread_mutex_init(&mutex,NULL);

	pthread_t tidA, tidB;
	pthread_create(&tidA, NULL, doit, NULL);
	pthread_create(&tidB, NULL, doit, NULL);
	/* wait for both threads to terminate */
	pthread_join(tidA, NULL);
	pthread_join(tidB, NULL);
	return 0;
}
//	int pthread_mutex_lock(pthread_mutex_t *mutex);
//	int pthread_mutex_trylock(pthread_mutex_t *mutex);
//	int pthread_mutex_unlock(pthread_mutex_t *mutex);

chunli@ubuntu:~/linux_c/thread$ gcc pthread_1.c -lpthread && ./a.out | tail
139995506951936: 9991
139995506951936: 9992
139995506951936: 9993
139995506951936: 9994
139995506951936: 9995
139995506951936: 9996
139995506951936: 9997
139995506951936: 9998
139995506951936: 9999
139995506951936: 10000
chunli@ubuntu:~/linux_c/thread$ gcc pthread_1.c -lpthread && ./a.out | tail
139808960182016: 9991
139808960182016: 9992
139808960182016: 9993
139808960182016: 9994
139808960182016: 9995
139808960182016: 9996
139808960182016: 9997
139808960182016: 9998
139808960182016: 9999
139808960182016: 10000
chunli@ubuntu:~/linux_c/thread$ gcc pthread_1.c -lpthread && ./a.out | tail
140152754497280: 9991
140152754497280: 9992
140152754497280: 9993
140152754497280: 9994
140152754497280: 9995
140152754497280: 9996
140152754497280: 9997
140152754497280: 9998
140152754497280: 9999
140152754497280: 10000
chunli@ubuntu:~/linux_c/thread$


读写锁:3个写线程,5个读线程,不加锁,并行处理

chunli@ubuntu:~/linux_c/thread$ cat pthread_2.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
int counter;
pthread_rwlock_t rwlock;

void *th_write(void *argc)
{
	while(1)
	{
		printf("write %zd counter=%d   ++counter=%d\n",(size_t)pthread_self(),counter,++counter);	
		sleep(1);
	}
}

void *th_read(void *argc)
{
	while(1)
	{
		printf("read %zd    %d\n",(size_t)pthread_self(),counter);	
		sleep(1);
	}
}

int main()
{
	int i = 0;
	pthread_t tid[8];
	pthread_rwlock_init(&rwlock,NULL);
	for(i = 0;i<3;i++)
	{
		pthread_create(&tid[i],NULL,th_write,NULL);
	}
	for(i = 0;i<5;i++)
	{
		pthread_create(&tid[i],NULL,th_read,NULL);
	}
	for(i = 0;i<8;i++)
	{
		pthread_join(tid[i],NULL);
	}
	

	return 0;
}
chunli@ubuntu:~/linux_c/thread$ gcc pthread_2.c -lpthread && ./a.out 
write 140196276619008 counter=1   ++counter=1
write 140196268226304 counter=2   ++counter=2
write 140196188256000 counter=3   ++counter=3
read 140196179863296    3
read 140196171470592    3
read 140196163077888    3
read 140196154685184    3
read 140196146292480    3
write 140196276619008 counter=4   ++counter=4
write 140196268226304 counter=5   ++counter=5
write 140196188256000 counter=6   ++counter=6
read 140196179863296    6
read 140196171470592    6
read 140196163077888    6
read 140196154685184    6
read 140196146292480    6
write 140196276619008 counter=7   ++counter=7
write 140196268226304 counter=8   ++counter=8
read 140196179863296    8
write 140196188256000 counter=9   ++counter=9
read 140196171470592    9
read 140196146292480    9
read 140196154685184    9
read 140196163077888    9
write 140196276619008 counter=10   ++counter=10
write 140196268226304 counter=11   ++counter=11
read 140196171470592    11
read 140196154685184    12
read 140196146292480    12
read 140196163077888    12
write 140196188256000 counter=12   ++counter=12
read 140196179863296    12
write 140196276619008 counter=13   ++counter=13
write 140196268226304 counter=14   ++counter=14
read 140196179863296    14
read 140196171470592    14
read 140196146292480    14
write 140196188256000 counter=15   ++counter=15
read 140196163077888    15
read 140196154685184    14
^C
chunli@ubuntu:~/linux_c/thread$


读写锁:3个写线程,5个读线程,加读写锁,串行处理

chunli@ubuntu:~/linux_c/thread$ cat pthread_2.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
int counter;
pthread_rwlock_t rwlock;

void *th_write(void *argc)
{
	while(1)
	{
		//写数据,加锁
		pthread_rwlock_wrlock(&rwlock);
		//printf函数 参数从右向左入栈
		printf("write %zd ++counter=%d   counter=%d\n",(size_t)pthread_self(),++counter,counter);	
		//解锁
		pthread_rwlock_unlock(&rwlock);
		usleep(100000);
	}
}

void *th_read(void *argc)
{
	while(1)
	{
		//读数据也可以加锁、解锁
		pthread_rwlock_wrlock(&rwlock);
		printf("read %zd    %d\n",(size_t)pthread_self(),counter);	
		pthread_rwlock_unlock(&rwlock);
		sleep(1);
	}
}

int main()
{
	int i = 0;
	pthread_t tid[8];
	pthread_rwlock_init(&rwlock,NULL);
	for(i = 0;i<3;i++)
	{
		pthread_create(&tid[i],NULL,th_write,NULL);
	}
	for(i = 0;i<5;i++)
	{
		pthread_create(&tid[i],NULL,th_read,NULL);
	}
	for(i = 0;i<8;i++)
	{
		pthread_join(tid[i],NULL);
	}
	

	return 0;
}

chunli@ubuntu:~/linux_c/thread$ gcc pthread_2.c -lpthread && ./a.out 
write 139990062577408 ++counter=1   counter=0
read 139989929146112    1
read 139989954324224    1
read 139990045792000    1
read 139989945931520    1
read 139989937538816    1
write 139990054184704 ++counter=2   counter=1
write 139989962716928 ++counter=3   counter=2
write 139990062577408 ++counter=4   counter=3
write 139990054184704 ++counter=5   counter=4
write 139989962716928 ++counter=6   counter=5
write 139990062577408 ++counter=7   counter=6
write 139990054184704 ++counter=8   counter=7
write 139989962716928 ++counter=9   counter=8
write 139990062577408 ++counter=10   counter=9
write 139990054184704 ++counter=11   counter=10
write 139989962716928 ++counter=12   counter=11
write 139990062577408 ++counter=13   counter=12
write 139990054184704 ++counter=14   counter=13
write 139989962716928 ++counter=15   counter=14
write 139990062577408 ++counter=16   counter=15
write 139990054184704 ++counter=17   counter=16
write 139989962716928 ++counter=18   counter=17
write 139990062577408 ++counter=19   counter=18
write 139990054184704 ++counter=20   counter=19
write 139989962716928 ++counter=21   counter=20
write 139990062577408 ++counter=22   counter=21
write 139990054184704 ++counter=23   counter=22
write 139989962716928 ++counter=24   counter=23
write 139990062577408 ++counter=25   counter=24
write 139989962716928 ++counter=26   counter=25
write 139990054184704 ++counter=27   counter=26
write 139990062577408 ++counter=28   counter=27
write 139989962716928 ++counter=29   counter=28
write 139990054184704 ++counter=30   counter=29
read 139989929146112    30
read 139989945931520    30
read 139990045792000    30
read 139989937538816    30
read 139989954324224    30
write 139990062577408 ++counter=31   counter=30
write 139989962716928 ++counter=32   counter=31
write 139990054184704 ++counter=33   counter=32
write 139990062577408 ++counter=34   counter=33
write 139989962716928 ++counter=35   counter=34
write 139990054184704 ++counter=36   counter=35
write 139990062577408 ++counter=37   counter=36
write 139989962716928 ++counter=38   counter=37
write 139990054184704 ++counter=39   counter=38
write 139990062577408 ++counter=40   counter=39
write 139989962716928 ++counter=41   counter=40
write 139990054184704 ++counter=42   counter=41
write 139990062577408 ++counter=43   counter=42
write 139989962716928 ++counter=44   counter=43
write 139990054184704 ++counter=45   counter=44
write 139990062577408 ++counter=46   counter=45
write 139989962716928 ++counter=47   counter=46
write 139990054184704 ++counter=48   counter=47
write 139990062577408 ++counter=49   counter=48
write 139989962716928 ++counter=50   counter=49
write 139990054184704 ++counter=51   counter=50
write 139990062577408 ++counter=52   counter=51
write 139989962716928 ++counter=53   counter=52
write 139990054184704 ++counter=54   counter=53
^C
chunli@ubuntu:~/linux_c/thread$


条件变量:生产消费者模型

2个消费者,1个生产者
chunli@ubuntu:~/linux_c/thread$ cat pthread_3.c 
#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

struct msg {
	struct msg *next;
	int num;
};

//全局变量
struct msg *head;
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;


void *consumer(void *p)
{
//pthread_cond_wait(&has_product, &lock)
//1,阻塞等待has_product被唤醒
//2,释放互斥锁,pthread_mutex_unlock(&lock)
//3,当被唤醒时,解除阻塞,并且重新去申请pthread_mutex_lock(&lock)
	struct msg *mp;
	while(1)
	{
		pthread_mutex_lock(&lock);
		while (head == NULL)
		{
			printf("等待产品生产\n");
			pthread_cond_wait(&has_product, &lock);//等待生产者来唤醒
			printf("产品生产OK\n");
		}
		mp = head;
		head = mp->next;
		pthread_mutex_unlock(&lock);
		printf("Consume %d\n", mp->num);
		free(mp);
		sleep(rand() % 5);
	}
}
void *producer(void *p)
{
	struct msg *mp;
	while(1)
	{
		mp = malloc(sizeof(struct msg));
		mp->num = rand() % 1000 + 1;
		printf("Produce %d\n", mp->num);
		pthread_mutex_lock(&lock);
		mp->next = head;
		head = mp;
		pthread_mutex_unlock(&lock);
		pthread_cond_signal(&has_product);//生产者有义务通知消费者
		sleep(rand() % 7);
	}
}

int main(int argc, char *argv[])
{
	pthread_t pid, cid;
	srand(time(NULL));
	pthread_create(&pid, NULL, producer, NULL);
	pthread_create(&pid, NULL, producer, NULL);
	pthread_create(&cid, NULL, consumer, NULL);
	pthread_join(pid, NULL);
	pthread_join(cid, NULL);
	return 0;
}

chunli@ubuntu:~/linux_c/thread$ gcc pthread_3.c -lpthread && ./a.out 
Produce 592
Produce 421
等待产品生产
产品生产OK
Consume 592
Consume 421
等待产品生产
Produce 719
产品生产OK
Consume 719
Produce 792
Consume 792
Produce 311
Consume 311
等待产品生产
Produce 196
产品生产OK
Consume 196
^C
chunli@ubuntu:~/linux_c/thread$


信号量

用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,

别的线程再进行某些动作

chunli@ubuntu:~/linux_c/thread$ cat pthread_4.c 
#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>

#define NUM 5
int queue[NUM];
sem_t blank_number, product_number;

void *producer(void *arg)
{
	int p = 0;
	while (1) 
	{
		sem_wait(&blank_number);
		queue[p] = rand() % 1000 + 1;
		printf("Produce %d\n", queue[p]);
		sem_post(&product_number);
		p = (p+1)%NUM;
		sleep(rand()%5);
	}
}

void *consumer(void *arg)
{
	int c = 0;
	while (1) 
	{
		sem_wait(&product_number);
		printf("Consume %d\n", queue[c]);
		queue[c] = 0;
		sem_post(&blank_number);
		c = (c+1)%NUM;
		sleep(rand()%5);
	}
}
int main(int argc, char *argv[])
{
	pthread_t pid, cid;
	sem_init(&blank_number, 0, NUM);
	sem_init(&product_number, 0, 0);
	pthread_create(&pid, NULL, producer, NULL);
	pthread_create(&cid, NULL, consumer, NULL);
	pthread_join(pid, NULL);
	pthread_join(cid, NULL);
	sem_destroy(&blank_number);
	sem_destroy(&product_number);
	return 0;
}
chunli@ubuntu:~/linux_c/thread$ gcc pthread_4.c -lpthread && ./a.out 
Produce 384
Consume 384
Produce 916
Consume 916
Produce 387
Consume 387
Produce 422
Consume 422
Produce 28
Consume 28
Produce 927
Consume 927
Produce 173
^C
chunli@ubuntu:~/linux_c/thread$


进程间锁

chunli@ubuntu:~/linux_c/thread$ cat pthread_5.c  
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
struct mt 
{
	int num;
	pthread_mutex_t mutex;
	pthread_mutexattr_t mutexattr;
};

int main(void)
{
	int fd, i;
	struct mt *mm;
	pid_t pid;
	fd = open("mt_test", O_CREAT | O_RDWR, 0777);
	/* 不需要write,文件里初始值为0 */
	ftruncate(fd, sizeof(*mm));
	mm = mmap(NULL, sizeof(*mm), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	close(fd);
	memset(mm, 0, sizeof(*mm));
	/* 初始化互斥对象属性 */
	pthread_mutexattr_init(&mm->mutexattr);
	/* 设置互斥对象为PTHREAD_PROCESS_SHARED共享,即可以在多个进程的线程访问,PTHREAD_PROCESS_PRIVATE
	   为同一进程的线程共享 */
	pthread_mutexattr_setpshared(&mm->mutexattr,PTHREAD_PROCESS_SHARED);
	pthread_mutex_init(&mm->mutex, &mm->mutexattr);
	pid = fork();
	if (pid == 0)
	{
		/* 加10次。相当于加10 */
		for (i=0;i<10;i++)
		{
			pthread_mutex_lock(&mm->mutex);
			(mm->num)++;
			printf("num++:%d\n",mm->num);
			pthread_mutex_unlock(&mm->mutex);
			sleep(1);
		}
	}
	else if (pid > 0) 
	{
		/* 父进程完成x+2,加10次,相当于加20 */
		for (i=0; i<10; i++)
		{
			pthread_mutex_lock(&mm->mutex);
			mm->num += 2;
			printf("num+=2:%d\n",mm->num);
			pthread_mutex_unlock(&mm->mutex);
			sleep(1);
		}
		wait(NULL);
	}
	pthread_mutex_destroy(&mm->mutex);
	pthread_mutexattr_destroy(&mm->mutexattr);
	/* 父子均需要释放 */
	munmap(mm,sizeof(*mm));
	unlink("mt_test");
	return 0;
}
chunli@ubuntu:~/linux_c/thread$ gcc pthread_5.c -lpthread && ./a.out 
num++:1
num+=2:3
num+=2:5
num++:6
num+=2:8
num++:9
num+=2:11
num++:12
num+=2:14
num++:15
num+=2:17
num++:18
num+=2:20
num++:21
^C
chunli@ubuntu:~/linux_c/thread$



文件锁:

chunli@ubuntu:~/linux_c/thread$ cat pthread_6.c 
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
void sys_err(char *str)
{
	perror(str);
	exit(1);
}
int main(int argc, char *argv[])
{
	int fd;
	struct flock f_lock;
	if (argc < 2) 
	{
		printf("./a.out filename\n");
		exit(1);
	}
	if ((fd = open(argv[1], O_RDWR)) < 0)
	{
		sys_err("open");
	}
	f_lock.l_type = F_WRLCK;
	//f_lock.l_type = F_RDLCK;
	f_lock.l_whence = SEEK_SET;
	f_lock.l_start = 0;
	f_lock.l_len = 0; //0表示整个文件加锁
	fcntl(fd, F_SETLKW, &f_lock);
	printf("get flock\n");
	sleep(10);
	f_lock.l_type = F_UNLCK;
	fcntl(fd, F_SETLKW, &f_lock);
	printf("un flock\n");
	close(fd);
	return 0;
}

窗口1
chunli@ubuntu:~/linux_c/thread$ gcc pthread_6.c -lpthread && ./a.out  haha 
get flock
un flock
chunli@ubuntu:~/linux_c/thread$ 

窗口2,快速键入
chunli@ubuntu:~/linux_c/thread$ ./a.out haha 

get flock
un flock
chunli@ubuntu:~/linux_c/thread$ 


可以看出当窗口1解锁之后,窗口2才出现加锁


习题


1.请同学们自己编写出死锁程序。


2.哲学家就餐,5个哲学家,但是只有5支筷子,每个哲学家双手各拿起一支筷子时,可以

进餐n秒(rand()%5)。分别用互斥量,信号量,条件变量实现实现。



死锁是在编写多线程并发时候所需要考虑的问题,在多线程软件使用多个互斥锁来保护共享资源时,如果设计不合理会出现多个锁相互嵌套并且都在等待彼此的锁被释放,这样就会出现死锁现象,让系统挂起一直相互等待下去。下面给个例子说明这一现象:


死锁的两种情况



技术分享


chunli@ubuntu:~/linux_c/thread$ cat pthread_7.c 
#include <stdio.h>  
#include <stdlib.h>  
#include <sys/types.h>  
#include <pthread.h>  
#include <signal.h>  
#include <unistd.h>  

pthread_mutex_t mutex_one,mutex_two;  
pthread_mutex_t mutex;  
pthread_cond_t cond;  

void *thread_routine_one(void *arg)  
{  
	pthread_cond_wait(&cond,&mutex);//确保two线程先运行  

	printf("thread_routine_one: lock mutex_one!\n");  
	pthread_mutex_lock(&mutex_one);  

	printf("thread_routine_one: lock mutex_two!\n");  
	pthread_mutex_lock(&mutex_two);//获取two锁,这个要等待two线程对two锁的释放  

	sleep(1);  
	printf("thread_routine_one: unlock mutex_two!\n");  
	pthread_mutex_unlock(&mutex_two);  

	printf("thread_routine_one: unlock mutex_one!\n");  
	pthread_mutex_unlock(&mutex_one);  

	return NULL;  
}  

void *thread_routine_two(void *arg)  
{  
	printf("thread_routine_two: lock mutex_two!\n");  
	pthread_mutex_lock(&mutex_two);//获取two锁  
	pthread_cond_signal(&cond);//让one线程运行  
	sleep(1);//休眠,让one可以先运行获取one锁  

	printf("thread_routine_two: lock mutex_one!\n");  

	pthread_mutex_lock(&mutex_one);//获取one锁,这个同样必须等待one线程多one锁的释放  

	/**这时出现死锁现象了,在two线程要等待one线程对one锁的释放,同时two锁没有释放 
	 * 然而在one线程需要等待two线程对two锁的释放,然后才会对one锁的释放!出现相互等待的过程**/  

	printf("thread_routine_two: unlock mutex_one!\n");  
	pthread_mutex_unlock(&mutex_one);  

	printf("thread_routine_two: unlock mutex_two!\n");  
	pthread_mutex_unlock(&mutex_two);  

	return NULL;  
}  

void main()  
{  
	pthread_t pthread_one,pthread_two;  
	pthread_mutex_init(&mutex_one,NULL);  
	pthread_mutex_init(&mutex_two,NULL);  
	pthread_mutex_init(&mutex,NULL);  

	pthread_cond_init(&cond,NULL);  

	pthread_create(&pthread_one,NULL,thread_routine_one,NULL);  
	pthread_create(&pthread_two,NULL,thread_routine_two,NULL);  

	while(1)  
	{
		sleep(1);  
	}
}
chunli@ubuntu:~/linux_c/thread$ gcc pthread_7.c -lpthread && ./a.out 
thread_routine_two: lock mutex_two!
thread_routine_one: lock mutex_one!
thread_routine_one: lock mutex_two!
thread_routine_two: lock mutex_one!


哲学家就餐问题:

chunli@ubuntu:~/linux_c/thread$ cat pthread_8.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/wait.h>

#ifdef  _SEM_SEMUN_UNDEFINED
union semun
{
	int val;
	struct semid_ds *buf;
	unsigned short *array;
	struct seminfo *__buf;
};
#endif

#define ERR_EXIT(m) 	do { 		perror(m); 		exit(EXIT_FAILURE); 	} while(0)

	int
wait_1fork(int no,int semid)
{
	//int left = no;
	//int right = (no + 1) % 5;
	struct sembuf sb = {no,-1,0};
	int ret;
	ret = semop(semid,&sb,1);
	if(ret < 0) {
		ERR_EXIT("semop");
	}
	return ret;
}

	int
free_1fork(int no,int semid)
{
	struct sembuf sb = {no,1,0};
	int ret;
	ret = semop(semid,&sb,1);
	if(ret < 0) {
		ERR_EXIT("semop");
	}
	return ret;
}

//这里表明叉子是一个临界资源
#define DELAY (rand() % 5 + 1)
//相当于P操作
	void
wait_for_2fork(int no,int semid)
{
	//哲学家左边的刀叉号数
	int left = no;
	//右边的刀叉
	int right = (no + 1) % 5;

	//刀叉值是两个
	//注意第一个参数是编号
	struct sembuf buf[2] = {
		{left,-1,0},
		{right,-1,0}
	};
	//信号集中有5个信号量,只是对其中的
	//资源sembuf进行操作
	semop(semid,buf,2);
}

//相当于V操作
	void
free_2fork(int no,int semid)
{
	int left = no;
	int right = (no + 1) % 5;
	struct sembuf buf[2] = {
		{left,1,0},
		{right,1,0}
	};
	semop(semid,buf,2);
}



void philosophere(int no,int semid)
{
	srand(getpid());
	for(;;) {
#if 1
		//这里采取的措施是当两把刀叉都可用的时候
		//哲学家才能吃饭,这样不相邻的哲学家就可
		//吃上饭
		printf("%d is thinking\n",no);
		sleep(DELAY);
		printf("%d is hungry\n",no);
		wait_for_2fork(no,semid);//拿到叉子才能吃饭
		printf("%d is eating\n",no);
		sleep(DELAY);
		free_2fork(no,semid);//释放叉子
#else
		//这段代码可能会造成死锁
		int left = no;
		int right = (no + 1) % 5;
		printf("%d is thinking\n",no);
		sleep(DELAY);
		printf("%d is hungry\n",no);
		wait_1fork(left,semid);
		sleep(DELAY);
		wait_1fork(right,semid);
		printf("%d is eating\n",no);
		sleep(DELAY);
		free_2fork(no,semid);
#endif
	}
}

	int
main(int argc,char *argv[])
{
	int semid;
	//创建信号量
	semid = semget(IPC_PRIVATE,5,IPC_CREAT | 0666);
	if(semid < 0) {
		ERR_EXIT("semid");
	}
	union semun su;
	su.val = 1;
	int i;
	for(i = 0;i < 5;++i) {
		//注意第二个参数也是索引
		semctl(semid,i,SETVAL,su);
	}
	//创建4个子进程
	int num = 0;
	pid_t pid;
	for(i = 1;i < 5;++i) {
		pid = fork();
		if(pid < 0) {
			ERR_EXIT("fork");
		}
		if(0 == pid) {
			num = i;
			break;
		}
	}
	//这里就是哲学家要做的事情
	philosophere(num,semid);
	return 0;
}

chunli@ubuntu:~/linux_c/thread$ gcc pthread_8.c -lpthread && ./a.out 
1 is thinking
0 is thinking
3 is thinking
2 is thinking
4 is thinking
1 is hungry
1 is eating
4 is hungry
4 is eating
0 is hungry
1 is thinking
3 is hungry
2 is hungry
2 is eating
4 is thinking
1 is hungry
0 is eating
2 is thinking
3 is eating
3 is thinking
0 is thinking
1 is eating
4 is hungry
4 is eating
2 is hungry
4 is thinking
3 is hungry
3 is eating
0 is hungry
^C


本文出自 “魂斗罗” 博客,谢绝转载!

Linux系统开发9 线程同步

原文:http://990487026.blog.51cto.com/10133282/1839608

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!