安装man文档linux
sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev
ps -Lf pid
,查看指定线程的LWP号。pthread_t pthread_self(void);
- 返回值:成功:0;失败:无!int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
示例数据库
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> void *thread_func(void *arg) { printf("In thread: thread id = %lu, pid = %u\n", pthread_self(), getpid()); return NULL; } int main() { pthread_t tid; int ret; printf("In main1: thread id = %lu, pid = %u\n", pthread_self(), getpid()); ret = pthread_create(&tid, NULL, thread_func, NULL); if(ret != 0){ fprintf(stderr, "pthread_create error:%s\n", strerror(ret)); exit(1); } sleep(1); printf("In main2: thread id = %lu, pid = %u\n", pthread_self(), getpid()); return 0; }
(void *)&i
,将线程主函数内改成i = *((int *)arg)
是否能够?不能够。示例编程
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> void *thread_func(void *arg) { int i = (int)arg; sleep(i); printf("%dth thread: thread id = %lu, pid = %u\n", i+1, pthread_self(), getpid()); return NULL; } int main() { pthread_t tid; int ret, i; for (i = 0; i<5; i++){ ret = pthread_create(&tid, NULL, thread_func, (void *)i); if(ret != 0){ fprintf(stderr, "pthread_create error:%s\n", strerror(ret)); exit(1); } } sleep(i); return 0; }
【练习】:设计程序,验证线程之间共享全局数据。数组
#include <stdio.h> #include <pthread.h> #include <stdlib.h> #include <unistd.h> int var = 100; void *tfn(void *arg) { var = 200; printf("thread\n"); return NULL; } int main(void) { printf("At first var = %d\n", var); pthread_t tid; pthread_create(&tid, NULL, tfn, NULL); sleep(1); printf("After pthread_create, var = %d\n", var); return 0; }
示例服务器
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> void *thread_func(void *arg) { int i = (int)arg; printf("%dth thread: thread id = %lu, pid = %u\n", i+1, pthread_self(), getpid()); return NULL; } int main() { pthread_t tid; int ret, i; for (i = 0; i<5; i++){ ret = pthread_create(&tid, NULL, thread_func, (void *)i); if(ret != 0){ fprintf(stderr, "pthread_create error:%s\n", strerror(ret)); exit(1); } } pthread_exit(NULL); }
int pthread_join(pthread_t thread, void **retval);
成功:0;失败:错误号。【练习】:参数retval非空用法。网络
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <pthread.h> typedef struct{ int a; int b; } exit_t; void *tfn(void *arg) { exit_t * ret; ret = malloc(sizeof(exit_t)); ret->a = 100; ret->b = 300; pthread_exit((void *)ret); } int main(void) { pthread_t tid; exit_t * retval; pthread_create(&tid, NULL, tfn, NULL); //调用pthread_join能够获取线程的退出状态 pthread_join(tid, (void **)&retval); printf("a = %d, b = %d\n", retval->a, retval->b); free(retval); return 0; }
【练习】:使用pthread_join函数将循环建立的多个子线程回收。数据结构
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> int var = 100; void * tfn(void * arg) { int i; i = (int)arg; sleep(i); if(i == 1){ var = 333; printf("var = %d\n", var); return var; } else if (i == 3) { var = 777; printf("I'm %dth pthread, pthread_id = %lu\n var = %d\n", i+1, pthread_self(), var); pthread_exit((void *)var); } else { printf("I'm %dth pthread, pthread_id = %lu\n var = %d\n", i+1, pthread_self(), var); pthread_exit((void *)var); } return NULL; } int main(void) { pthread_t tid[5]; int i; int *ret[5]; for(i = 0; i < 5; i++) pthread_create(&tid[i], NULL, tfn, (void *)i); for(i = 0; i < 5; i++){ pthread_join(tid[i], (void **)&ret[i]); printf("-------%d 's ret = %d\n'", i, (int)ret[i]); } printf("I'm main pthread tid = %lu\t var = %d\n", pthread_self(), var); sleep(i); return 0; }
int pthread_detach(pthread_t thread);
,成功:0;失败:错误号。通常状况下,线程终止后,其终止状态一直保留到其它线程调用pthread_join获取它的状态为止。可是线程也能够被置为detach状态,这样的线程一旦终止就马上回收它占用的全部资源,而不保留终止状态。不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL错误。也就是说,若是已经对一个线程调用了pthread_detach就不能再调用pthread_join了。多线程
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <pthread.h> void *tfn(void *arg) { int n = 3; while(n--){ printf("thread count %d\n", n); sleep(1); } return (void *)1; } int main(void) { pthread_t tid; void *tret; int err; #if 0 //经过线程属性来设置游离态 pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(&tid, &attr, tfn, NULL); #else pthread_create(&tid, NULL, tfn, NULL); //让线程分离-----自动退出,无系统残留资源 pthread_detach(tid); #endif while(1){ err = pthread_join(tid, &tret); printf("------------err = %d\n", err); if(err != 0) fprintf(stderr, "thread_join error : %s\n", strerror(err)); else fprintf(stderr, "thread exit code %d\n", (int)tret); } }
int pthread_cancel(pthread_t thread);
,成功:0;失败:错误号。#define PTHREAD_CANCELED((void *)-1)
。所以当咱们对一个已经被取消的线程使用pthread_join回收时,获得的返回值为-1。【练习】:终止线程的三种方法。注意“取消点”的概念。并发
#include <stdio.h> #include <unistd.h> #include <pthread.h> #include <stdlib.h> void *tfn1(void *arg) { printf("thread 1 returning\n"); return (void *)111; } void *tfn2(void *arg) { printf("thread 2 exiting\n"); pthread_exit((void *)222); } void *tfn3(void *arg) { while(1){ //printf("thread 3: I'm going to die in 3 seconds ... \n"); //sleep(1); pthread_testcancel(); //本身添加取消点 } return (void *)666; } int main() { pthread_t tid; void *tret = NULL; pthread_create(&tid, NULL, tfn1, NULL); pthread_join(tid, &tret); printf("thread 1 exit code = %d\n\n", (int)tret); pthread_create(&tid, NULL, tfn2, NULL); pthread_join(tid, &tret); printf("thread 2 exit code = %d\n\n", (int)tret); pthread_create(&tid, NULL, tfn3, NULL); sleep(3); pthread_cancel(tid); pthread_join(tid, &tret); printf("thread 3 exit code = %d\n", (int)tret); }
int pthread_equal(pthread_t t1, pthread_t t2);
进程 线程 fork pthread_create 建立 exit pthread_exit 退出 wait pthread_join 等待 kill pthread_cancel 杀死 getpid pthread_self 取得ID pthread_detach 分离
本节做为指引性介绍,Linux下线程的属性是能够根据实际项目须要进行设置,以前咱们讨论的线程都是采用线程的默认属性,默认属性已经能够解决绝大多数开发时遇到的问题。如咱们对程序的性能提出更高的要求,那么须要设置线程属性,好比能够经过设置线程栈的大小来下降内存的使用,增长最大线程个数。
typedef struct{
int etachstate; //线程的分离状态
int schedpolicy; //线程调度策略
struct sched_param schedparam; //线程的调度参数
int inheritsched; //线程的继承性
int scope; //线程的做用域
size_t guardsize; //线程栈末尾的警惕缓冲区大小
int stackaddr_set; //线程的栈设置
void* stackaddr; //线程的位置
size_t stacksize; //线程的大小
} pthread_attr_t;函数
线程属性主要包括以下属性:做用域(scope)、栈尺寸(stack size)、栈地址(stack address)、优先级(priority)、分离的状态(detached state)、调度策略和参数(scheduling policy and parameters)。默认的属性为非绑定、非分离、缺省的堆栈、与父进程一样级别的优先级。
int pthread_attr_init(pthread_attr_t *attr);
,成功:0; 失败:错误号。int pthread_attr_destroy(pthread_attr_t *attr);
,成功:0;失败:错误号。int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);
这里要注意的一点是,若是设置一个线程为分离线程,而这个线程运行又很是快,它极可能在pthread_create函数返回以前就终止了,它终止之后就可能将线程号和系统资源移交给其余的线程使用,这样调用pthread_create的线程就获得了错误的线程号。要避免这种状况能够采起必定的同步措施,最简单的方法之一是能够在被建立的线程里调用pthread_cond_timedwait函数,让这个线程等待一下子,留出足够的时间让函数pthread_create返回。设置一段等待时间,是在多线程编程里经常使用的方法。可是注意不要使用诸如wait()之类的函数,它们是使整个进程睡眠,并不能解决同步的问题。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> void *thread_func(void *arg) { pthread_exit((void *)11); } int main() { pthread_t tid; int ret; pthread_attr_t attr; ret = pthread_attr_init(&attr); if(ret != 0){ fprintf(stderr, "pthread_attr_init error:%s\n", strerror(ret)); exit(1); } pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); ret = pthread_create(&tid, &attr, thread_func, NULL); if(ret != 0){ fprintf(stderr, "pthread_create error:%s\n", strerror(ret)); exit(1); } ret = pthread_join(tid, NULL); if(ret != 0){ fprintf(stderr, "pthread_join error:%s\n", strerror(ret)); exit(1); } pthread_exit((void *)1); return 0; }
int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize);
#include <stdio.h> #include <pthread.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #define SIZE 0X10000 void *th_fun(void *arg) { while(1) sleep(1); } int main() { pthread_t tid; int err, detachstate, i = 1; pthread_attr_t attr; size_t stacksize; void *stackaddr; pthread_attr_init(&attr); pthread_attr_getstack(&attr, &stackaddr, &stacksize); pthread_attr_getdetachstate(&attr, &detachstate); //默认是分离态 if(detachstate == PTHREAD_CREATE_DETACHED) printf("thread detached\n"); //默认是非分离 else if (detachstate == PTHREAD_CREATE_JOINABLE) printf("thread join\n"); else printf("thread un known\n"); //设置线程分离属性 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); while(1){ //在堆上申请内存,指定线程栈的起始地址和大小 stackaddr = malloc(SIZE); if(stackaddr == NULL){ perror("malloc"); exit(1); } stacksize = SIZE; //借助线程的属性,修改线程栈空间大小 pthread_attr_setstack(&attr, stackaddr, stacksize); err = pthread_create(&tid, &attr, th_fun, NULL); if(err != 0){ printf("%s\n", strerror(err)); exit(1); } printf("%d\n", i++); } pthread_attr_destroy(&attr); }
而,编程中、通讯中所说的同步与生活中你们印象中的同步概念略有差别。“同”字应是指协同、协助、互相配合。主旨在协同步调,按预约的前后次序运行。
所以,全部“多个控制流,共同操做一个共享资源”的状况,都须要同步。
全部只能从第三点着手解决。使多个线程在访问共享资源的时候,出现互斥。
所以,即便有了mutex,若是有线程不按规则来访问数据,依然会形成数据混乱。
int pthread_mutex_init(pthread_mutex_t * restrict mutex, const pthread_mutexattr_t * restrict attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_init(&mutex, NULL);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
trylock加锁失败直接返回错误号(如:EBUSY),不阻塞。
看以下程序:该程序是很是典型的,因为共享、竞争而没有加任何同步机制,致使产生于时间有关的错误,形成数据混乱。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> void *tfn(void *arg) { srand(time(NULL)); while(1){ printf("hello "); //模拟长时间操做共享资源,致使CPU易主,产生与时间有关的错误 sleep(rand() % 3); printf("world\n"); sleep(rand() % 3); } return NULL; } int main(void) { pthread_t tid; srand(time(NULL)); pthread_create(&tid, NULL, tfn, NULL); while(1){ printf("HELLO "); sleep(rand() % 3); printf("WORLD\n"); sleep(rand() % 3); } return 0; }
五、main中加pthread_cancel()将子线程取消。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> //定义锁 pthread_mutex_t mutex; void *tfn(void *arg) { srand(time(NULL)); while(1){ //加锁 pthread_mutex_lock(&mutex); printf("hello "); //模拟长时间操做共享资源,致使CPU易主,产生与时间有关的错误 sleep(rand() % 3); printf("world\n"); //解锁 pthread_mutex_unlock(&mutex); sleep(rand() % 3); //添加检查点 pthread_testcancel(); } return NULL; } int main(void) { int flag = 5; pthread_t tid; srand(time(NULL)); //锁初始化 pthread_mutex_init(&mutex, NULL); //mutex = 1 pthread_create(&tid, NULL, tfn, NULL); while(flag--){ //加锁 pthread_mutex_lock(&mutex); printf("HELLO "); sleep(rand() % 3); printf("WORLD\n"); //解锁 pthread_mutex_unlock(&mutex); sleep(rand() % 3); } //取消子线程 pthread_cancel(tid); pthread_join(tid, NULL); //锁销毁 pthread_mutex_destroy(&mutex); return 0; }
结论:在访问共享资源前加锁,访问结束后当即解锁。锁的“粒度”应越小越好。
示例
#include <stdio.h> #include <unistd.h> #include <pthread.h> int counter; pthread_rwlock_t rwlock; void *th_write(void *arg) { int t; int i = (int)arg; while(1){ t = counter; usleep(1000); pthread_rwlock_wrlock(&rwlock); printf("======write %d: %lu: counter=%d ++counter=%d\n", i, pthread_self(), t, ++counter); pthread_rwlock_unlock(&rwlock); usleep(5000); } return NULL; } void *th_read(void *arg) { int i = (int)arg; while(1){ pthread_rwlock_rdlock(&rwlock); printf("======read %d: %lu: %d\n", i, pthread_self(), counter); pthread_rwlock_unlock(&rwlock); usleep(900); } return NULL; } //3个线程不定时写全局资源,5个线程不定时读同一全局资源 int main() { int i; pthread_t tid[8]; //初始读写锁 pthread_rwlock_init(&rwlock, NULL); for(i = 0; i < 3; i++) pthread_create(&tid[i], NULL, th_write, (void *)i); for(i = 0; i < 5; i++) pthread_create(&tid[i+3], NULL, th_read, (void *)i); for(i = 0; i < 8; i++) pthread_join(tid[i], NULL); //释放读写锁 pthread_rwlock_destroy(&rwlock); return 0; }
int pthread_cond_init(pthread_cond_t * restrict cond, const pthread_condattr_t * restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZED;
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t * restrict cond, pthread_mutex_t * restrict mutex);
int pthread_cond_timedwait(pthread_cond_t * restrict cond, pthread_mutex_t * restrict mutex, const struct timespec * restrict abstime);
参3:参看man sem_timedwait
函数,查看struct timespec结构体。
struct timespec{ time_t tv_sec; /*seconds*/ 秒 long tv_nsec; /*nanoseconds*/ 纳秒 };
如:time(NULL)返回的就是绝对时间。而alarm(1)是相对时间,相对当前时间定时1秒钟。
struct timespec t = {1,0}; pthread_cond_timedwait(&cond, &mutex, &t); 只能定时到1970年1月1日 00:00:01秒(早已通过去)
在讲解setitimer函数时咱们还提到另外一种时间类型
struct timeval{ time_t tv_sec; /*seconds*/ 秒 suseconds_t tv_usec; /*microseconds*/ 微秒 };
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
看以下示例,使用条件变量模拟生产者、消费者问题:
/*借助条件变量模拟,生产者-消费者问题*/ #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <pthread.h> /*链表做为共享数据,需被互斥量保护*/ struct msg { struct msg *next; int num; }; struct msg *head; struct msg *mp; /*静态初始化一个条件变量和一个互斥量*/ pthread_cond_t has_product = PTHREAD_COND_INITIALIZER; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; void *consumer(void *p) { for(;;){ pthread_mutex_lock(&lock); while(head == NULL){ //头指针为空,说明没有节点 pthread_cond_wait(&has_product, &lock); } mp = head; head = mp->next; //模拟消费掉一个产品 pthread_mutex_unlock(&lock); printf("-Consume ---%d\n", mp->num); free(mp); sleep(rand() % 5); } } void *producer(void *p) { for(;;){ 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() % 5); } } int main(int argc, char * argv) { pthread_t pid, cid; srand(time(NULL)); pthread_create(&pid, NULL, producer, NULL); pthread_create(&cid, NULL, consumer, NULL); pthread_join(pid, NULL); pthread_join(cid, NULL); return 0; }
信号量,是相对折中的一种处理方式,既能保证同步,数据不混乱,又能提升线程并发。
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_destroy(sem_t *sem);
int sem_wait(sem_t *sem);
int sem_post(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
参2:abs_timeout采用的是绝对时间。
【练习】:使用信号量完成线程间同步,模拟生产者,消费者问题。
/*信号量实现生产者消费者问题*/ #include <stdio.h> #include <unistd.h> #include <pthread.h> #include <stdlib.h> #include <semaphore.h> #define NUM 5 int queue[NUM]; //全局数组实现环形队列 sem_t blank_number, product_number; //空格子信号量,产品信号量 void *producer(void *arg) { int i = 0; while(1) { sem_wait(&blank_number); //生产者将空格子数--,为0则阻塞等待 queue[i] = rand() % 1000 + 1; //生产一个产品 printf("----Produce----%d\n", queue[i]); sem_post(&product_number); //将产品数++ i = (i+1) % NUM; //借助下标实现环形 sleep(rand() % 3); } return NULL; } void *consumer(void *arg) { int i = 0; while(1){ sem_wait(&product_number); //消费者将产品数--,为0则阻塞等待 printf("--Consume---%d\n", queue[i]); queue[i] = 0; //消费一个产品 sem_post(&blank_number); //消费掉之后,将空格子数++ i = (i+1) % NUM; //借助下标实现环形 sleep(rand() % 3); } return NULL; } int main() { pthread_t pid, cid; sem_init(&blank_number, 0, NUM); //初始化空格子信号量为5 sem_init(&product_number, 0, 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; }
因此有:
T生产者主函数 { sem_wait(S空); 生产... sem_post(S满) } T消费者主函数 { sem_wait(S满); 消费... sem_post(S空) }
【做业】:结合生产者消费者信号量模型,揣摩sem_timedwait函数做用。编程实现,一个线程读用户输入,另外一个线程打印“hello world”。若是用户无输入,则每隔5秒向屏幕打印一个“hello world”;若是用户有输入,马上打印“hello world”到屏幕。
进程间也可使用互斥锁,来达到同步的目的。但应在pthread_mutex_init初始化以前,修改其属性为进程间共享。mutex的属性修改函数主要有如下几个。
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);
进程间mutex示例
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <pthread.h> #include <sys/mman.h> #include <sys/wait.h> struct mt { int num; pthread_mutex_t mutex; pthread_mutexattr_t mutexattr; }; int main() { int i; struct mt *mm; pid_t pid; mm = mmap(NULL, sizeof(*mm), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0); memset(mm, 0, sizeof(*mm)); pthread_mutexattr_init(&mm->mutexattr); //初始化mutex属性对象 pthread_mutexattr_setpshared(&mm->mutexattr, PTHREAD_PROCESS_SHARED); //修改属性为进程间共享 pthread_mutex_init(&mm->mutex, &mm->mutexattr); //初始化一把mutex锁 pid = fork(); if(pid == 0){ for(i = 0; i < 10; i++){ pthread_mutex_lock(&mm->mutex); (mm->num)++; printf("-Child------------num++ %d\n", mm->num); pthread_mutex_unlock(&mm->mutex); sleep(1); } } else if(pid > 0){ for(i = 0; i < 10; i++){ sleep(1); pthread_mutex_lock(&mm->mutex); mm->num+=2; printf("-------parent-----num+=2 %d\n", mm->num); pthread_mutex_unlock(&mm->mutex); } wait(NULL); } pthread_mutexattr_destroy(&mm->mutexattr); //销毁mutex属性对象 pthread_mutex_destroy(&mm->mutex); //销毁mutex munmap(mm,sizeof(*mm)); //释放映射区 return 0; }
参3:
struct flock { ... short l_type; /* 锁的类型: F_RDLCK, F_WRLCK, F_UNLCK */ short l_whence; /* 偏移位置: SEEK_SET, SEEK_CUR, SEEK_END */ off_t l_start; /* 起始偏移:1000*/ off_t l_len; /* 长度:0表示整个文件加锁 */ pid_t l_pid; /* 持有该锁的进程ID:F_GETLK, F_OFD_GETLK */ ... };
进程间文件锁示例
#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; }
void *tfn(void *arg)
,使用参数来表示线程编号:int i = (int)arg;
5支筷子,在逻辑上造成环,分别对应5个哲学家。
A B C D E 0 1 2 3 4
因此有:
if(i == 4) left = i, right = 0; else left = i, right = i + 1;
因此以上if else语句应改成
if(i == 4) left = 0, right = i; else left = i, right = i + 1;
然后,首先让哲学家尝试加左手锁:
while(1){ pthread_mutex_lock(&m[left]); 若是加锁成功,函数返回再加右手锁,若是失败,应当即释放左手锁,等待。 若左右手都加锁成功 --> 吃 --> 吃完 --> 释放锁(应先释放右手、再释放左手,是加锁顺序的逆序) }
子进程中:
if(i == 4) left = 0, right = 4; else left = i, right = i + 1; while(1){ 使用sem_wait(&s[left])锁左手,尝试锁右手,若成功 --> 吃;若不成功 --> 将左手锁释放。 吃完后,先释放右手锁,再释放左手锁。 }