设为首页 加入收藏

TOP

线程同步(二)
2019-09-15 00:33:37 】 浏览:90
Tags:线程 同步
clock_gettime(CLOCK_REALTIME, &time); tmp_time = localtime(&time.tv_sec); strftime(s, sizeof(s), "%r", tmp_time); printf("the time is now %s\n", s); pthread_mutex_unlock(&mutex3); } int main() { pthread_t tid1; pthread_t tid2; pthread_t tid3; /*测试pthread_mutex_lock和pthread_mutex_trylock*/ pthread_mutex_init(&mutex1, NULL); pthread_mutex_init(&mutex2, NULL); pthread_create(&tid1, NULL, thread1_start, NULL); pthread_create(&tid2, NULL, thread2_start, NULL); if (pthread_join(tid1, NULL) == 0) { pthread_mutex_destroy(&mutex1); } if (pthread_join(tid2, NULL) == 0) { pthread_mutex_destroy(&mutex2); } /*测试pthread_mutex_timedlock*/ pthread_mutex_init(&mutex3, NULL); pthread_create(&tid3, NULL, thread3_start, NULL); if (pthread_join(tid3, NULL) == 0) { pthread_mutex_destroy(&mutex3); } return 0; }

3. 避免死锁

线程的死锁概念

线程间死锁,指的是线程间相互等待临界资源而造成彼此无法继续执行的现象。

产生死锁的四个必要条件

  • 互斥条件:资源同时只能被一个线程使用,此时若有其他线程请求该资源,则请求线程必须等待
  • 不可剥夺条件:线程获得的资源在未使用完毕前,不能被其他线程抢夺,只能由获得该资源的线程主动释放
  • 请求与保持条件:线程已经至少得到了一个资源,但又提出了新的资源请求,而新的资源已被其他线程占有,此时请求线程被阻塞,但对自己已获得的资源保持不放
  • 循环等待条件:存在一个资源等待环,环中每一个线程都占有下一个线程所需的至少一个资源

直观上看,循环等待条件似乎和死锁的定义一样,其实不然,因为死锁定义中的要求更为严格:

  • 循环等待条件要求P(i+1)需要的资源,至少有一个来自P(i)即可
  • 死锁定义要求P(i+1)需要的资源,由且仅由P(i)提供

如何避免死锁

  • 所有线程以相同顺序加锁
  • 给所有的临界资源分配一个唯一的序号,对应的线程锁也分配同样的序号,系统中的所有线程按照严格递增的次序请求资源
  • 使用pthread_mutex_trylock尝试加锁,若失败就放弃上锁,同时释放已占有的锁
  • 使用pthread_mutex_timedlock限时加锁,若超时就放弃上锁,同时释放已占有的锁

4. 条件变量

条件变量概念

  • 条件变量是线程另一种可用的同步机制,它给多线程提供了一个回合的场所
  • 条件变量本身需要由互斥锁保护,线程在改变条件之前必须先上锁,其他线程在获得互斥锁之前不会知道条件发生了改变
  • 条件变量和互斥锁一起使用,可以使线程以无竞争的方式等待特定条件的发生

条件变量基本API

初始化与销毁

条件变量是用pthread_cond_t数据类型表示的,和互斥锁类似,条件变量的初始化方法也有两种:

  • 设置为常量PTHREAD_COND_INITIALIZER,只适用于静态分配的条件变量
  • 调用pthread_cond_init函数,适用于静态分配和动态分配的条件变量

条件变量使用完以后,可以调用pthread_cond_destroy进行销毁,同样的,如果是动态分配的条件变量,在释放内存前,该操作也是必须的。

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

//两个函数的返回值:成功返回0,失败返回错误编号
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
int pthread_cond_destroy(pthread_cond_t *cond);

其中,pthread_cond_init的第二个参数attr用于设置条件变量的属性,如果要使用默认属性,只需把attr设为NULL。

等待条件满足

//两个函数的返回值:成功返回0,失败返回错误编号
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *timeout);

可以调用pthread_cond_wait函数等待条件满足,使用步骤如下,传递给函数的互斥锁对条件进行保护,在条件满足之前,调用线程将一直阻塞。

  • 调用线程将锁住的互斥量传给pthread_cond_wait
  • pthread_cond_wait自动把调用线程放到等待条件的线程列表上,然后对互斥锁解锁
  • 当条件满足,pthread_cond_wait返回时,互斥锁再次被锁住
  • pthread_cond_wait返回后,调用线程再对互斥锁解锁

pthread_cond_timedwait是一个限时等待条件满足的函数,如果发生超时时条件还没满足,pthread_cond_timedwait将重新对互斥锁上锁,然后返回ETIMEDOUT错误。

注意:当条件满足从pthread_cond_wait和pthread_cond_timedwait返回时,调用线程必须重新计算条件,因为另一个线程可能已经在运行并改变了条件。

给线程发信号

有两个函数可以用于通知线程条件已经满足:

  • pthread_cond_signal至少能唤醒一个等待该条件的线程
  • pthread_cond_broadcast可以唤醒等待该条件的所有线程
//两个函数的返回值:成功返回0,失败返回错误编号
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);

在调用上面两个函数时,我们说这是在给线程发信号,注意,一定要先获取互斥锁,再改变条件,然后给线程发信号,最后再对互斥锁解锁。

示例代码

/*
 * 结合使用条件变量和互斥锁进行线程同步
*/

#include <pthread.h>
#include <stdio.h>

static pthread
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Ubuntu14.04中stopping log initi.. 下一篇Dockfile 生成docker镜像文件大小..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目