标签:同步 栈设置 长度 after ber man har clone 写入
安装man文档
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);
【练习】:创建一个新线程,打印线程ID。注意:链接线程库-lpthread
示例
#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;
}
调用该函数的线程将挂起等待,直到ID为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:
【练习】:使用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;
主要结构体成员
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);
}
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);
看如下程序:该程序是非常典型的,由于共享、竞争而没有加任何同步机制,导致产生于时间有关的错误,造成数据混乱。
#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;
}
【练习】:修改该程序,使用mutex互斥锁进行同步。
5、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;
}
基本操作
pthread_cond_init函数
int pthread_cond_init(pthread_cond_t * restrict cond, const pthread_condattr_t * restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZED;
pthread_cond_destroy函数
int pthread_cond_destroy(pthread_cond_t *cond);
pthread_cond_wait函数
int pthread_cond_wait(pthread_cond_t * restrict cond, pthread_mutex_t * restrict mutex);
pthread_cond_timedwait函数
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*/ 纳秒
};
形参abstime:绝对时间。
如: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*/ 微秒
};
pthread_cond_signal函数
int pthread_cond_signal(pthread_cond_t *cond);
pthread_cond_broadcast函数
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);
【练习】:使用信号量完成线程间同步,模拟生产者,消费者问题。
/*信号量实现生产者消费者问题*/
#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空)
}
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;
}
int fcntl(int fd, int cmd, ... /* arg */ );
参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]); 如果加锁成功,函数返回再加右手锁,如果失败,应立即释放左手锁,等待。
若左右手都加锁成功 --> 吃 --> 吃完 --> 释放锁(应先释放右手、再释放左手,是加锁顺序的逆序)
}
主线程(main)中,初始化5把锁,销毁5把锁,创建5个线程(并将i传递给线程主函数),回收5个线程。
实现:
子进程中:
if(i == 4)
left = 0, right = 4;
else
left = i, right = i + 1;
while(1){
使用sem_wait(&s[left])锁左手,尝试锁右手,若成功 --> 吃;若不成功 --> 将左手锁释放。
吃完后,先释放右手锁,再释放左手锁。
}
【重点注意】
标签:同步 栈设置 长度 after ber man har clone 写入
原文地址:http://www.cnblogs.com/zfc2201/p/6288191.html