【本文谢绝转载原文来自http://990487026.blog.51cto.com】
《大纲》 Linux系统编程8 线程同步 多线程共享资源,不加锁,同步互斥演示 多线程共享资源,加锁,同步互斥演示 读写锁:3个写线程,5个读线程,不加锁,并行处理 读写锁:3个写线程,5个读线程,加读写锁,串行处理 条件变量:生产消费者模型 信号量 进程间锁 文件锁: 习题 死锁,哲学家就餐
多线程共享资源,不加锁,同步互斥演示
chunli@ubuntu:~/linux_c/thread$ cat pthread_1.c #include#include #include #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#include #include #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: ××× 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: ××× 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: ××× 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#include #include #include #include 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#include #include #include #include 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#include #include #include 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$
生产者消费者模型2
chunli@linux:~$ cat main.c /*借助条件变量模拟 生产者-消费者 问题*/ #include#include #include #include /*链表作为公享数据,需被互斥量保护*/ 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) { struct msg *mp; while(1) { pthread_mutex_lock(&lock); while (head == NULL) //检查条件是否满足 { pthread_cond_wait(&has_product, &lock);//函数内部:解锁, //1> pthread_cond_wait所做的第一件事就是同时对互斥对象解锁 //2>等待条件,阻塞 //3>线程被叫醒之后,将重新锁定mymutex } mp = head; head = mp->next; //模拟消费掉一个产品 pthread_mutex_unlock(&lock); printf("-Consume %lu---%d\n", pthread_self(), mp->num); free(mp); sleep(rand() % 5); } } void *producer(void *p) { struct msg *mp; while(1) { mp = malloc(sizeof(struct msg)); mp->num = rand() % 50 + 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() % 3); } } int main(int argc, char *argv[]) { pthread_t pid, cid; srand(time(NULL)); pthread_create(&cid, NULL, consumer, NULL); pthread_create(&cid, NULL, consumer, NULL); pthread_create(&cid, NULL, consumer, NULL); pthread_create(&pid, NULL, producer, NULL); //第1个生产者 pthread_join(pid, NULL); pthread_join(cid, NULL); return 0; } chunli@linux:~$ gcc main.c -lpthread -Wall && ./a.out -Produce -------------41 -Consume 139737504610048---41 -Produce -------------45 -Produce -------------21 -Produce -------------26 -Consume 139737487824640---26 -Consume 139737496217344---21 -Produce -------------1 -Consume 139737496217344---1 -Produce -------------16 -Consume 139737504610048---16 -Produce -------------2 -Produce -------------23 -Consume 139737487824640---23 -Consume 139737487824640---2 -Consume 139737496217344---45 -Produce -------------8 -Consume 139737504610048---8 -Produce -------------21 -Produce -------------13 -Produce -------------48 -Produce -------------16 -Consume 139737487824640---16 -Consume 139737487824640---48 -Consume 139737496217344---13 -Consume 139737496217344---21 ^C chunli@linux:~$
信号量
用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,
别的线程再进行某些动作
chunli@ubuntu:~/linux_c/thread$ cat pthread_4.c #include#include #include #include #include #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#include #include #include #include #include #include #include #include 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#include #include #include #include #include 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#include #include #include #include #include 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#include #include #include #include #include #include #include #include #include #include #include #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