Linux之线程同步——nptl线程库(二)(施工中)

Linux之线程同步——nptl线程库(二)(基础代码)

https://mp.csdn.net/postedit/90573953

 

提问:

  1. 线程同步是什么意思?为什么需要线程同步?不同步会导致什么后果?
  2. 线程同步有什么方法,接口?如何使用?
  3. 如何使用线程条件变量?

基本常识:

  • 临界区(critical section)是指访问某一共享资源代码片段。
  • 原子操作(atomic operation)是指访问同一共享资源其他线程不应中断该片段执行。
  • 尽管C语言的运算符看似简单,其操作未必属于原子操作
  • 自动变量(Automatic Variable)指的是局部作用域变量
  • 死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

 

英文缩写与全称:

  • futex 全称为fast user space mutex 即快速用户空间互斥量。
  • mutual exclusion 即互斥。
  • condition variable 即条件变量

1.线程同步是什么意思?为什么需要线程同步?不同步会导致什么后果?

  • 同步就是协同步调,按预定的先后次序进行运行。如进程、线程同步,可理解为进程或线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行;B依言执行,再将结果给A;A再继续操作。(摘自百度百科)
  • 对于为什么需要线程同步?和不同步导致的后果?可以参考基本代码中的第一个例子(链接在文章顶部)。

2.线程同步有什么方法,接口?如何使用?

  • 线程同步的两个工具:互斥量(mutex)和条件变量(condition variable)。互斥量可以帮助线程同步对共享资源的使用,条件变量则是在此之外的拾遗补缺,允许线程相互通知共享变量的状态发生了变化。

一、互斥量

互斥量使用和接口

#include<pthread.h>

pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

静态分配互斥量。

int pthread_mutex_lock(pthread_mutex_t *mutex);

锁定某一互斥量。
成功返回0,失败返回错误号(正数)。
参数mutex表示互斥量。

int pthread_mutex_unlock(pthread_mutex_t *mutex);

将某一互斥量解锁。
成功返回0,失败返回错误号(正数)。
参数mutex表示互斥量。
  • 对于mutex互斥量,可以理解为0锁定状态,1未锁定状态。线程1访问时,如果mutex为1,则线程让mutex减一,然后进入里面。这时候其他线程想要访问,但由于mutex为0,所以其他线程等待。直到线程1访问结束,调用pthread_mutex_unlock()让mutex加一,表示自身使用完毕。其他线程才能开始访问临界区,当然多个线程谁先访问,这是不确定的。
  • 使用案例在代码段(顶)。
  • Pthreads API 提供了 pthread_mutex_trylock()和pthread_mutex_timedlock()。这两个函数与pthread_mutex_lock()有一些区别,可以参考手册页(manual page)来使用。

动态化初始互斥量及其销毁

  • 静态初始值PTHREAD_MUTEX_INITIALIZER,只能用于如下互斥量进行初始化:经由静态分配且携带默认属性。其他情况下,必须调用pthread_mutex_init()对互斥量进行动态初始化。
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t* attr);

动态初始化互斥量。
成功返回0,失败返回对应错误号。
参数mutex为互斥量
参数attr是指向pthread_mutexattr_t类型对象的指针,该对象在函数调用前已经经过了初始化处理,用于定义互斥量的属性。
若将attr参数置为NULL,则互斥量的各种属性会取默认值。
  • SUSv3规定,初始化一个已初始化的互斥量将导致未定义的行为,应当避免这一行为。
  • 如下情况必须使用动态初始化:
  • 动态分配于堆中的互斥量。
  • 互斥量是在栈中分配的自动变量。
  • 初始化经由静态分配,且不使用默认属性的互斥量。
int pthread_mutex_destroy(pthread_mutex_t *mutex);

销毁动态分配的互斥量。
成功返回0,失败返回对应错误号。
  • 当不再需要经由自动或动态分配的互斥量时,应使用pthread_mutex_destroy()将其销毁。(静态分配的不需要)
  • 只有当互斥量处于未锁定状态,且后续也无任何线程企图锁定它时,将其销毁才是安全的。若互斥量驻留于动态分配的一片内存区域中,应在释放(free)此内存区域前才将其销毁。对于自动分配的互斥量,也应在宿主函数返回前将其销毁。
  • 经由pthread_mutex_destroy()销毁的互斥量,可调用pthread_mutex_init()对其重新初始化。

互斥量的属性

  • 由于很懒加上时间不够,而且自身也不太懂,这一段跳过(有空再来补),有兴趣可以看书或网上查。(万分抱歉)
  • 放了一个书上的例子在代码区(顶)3。

 

二、通知状态的改变:条件变量(condition variable)

  • 互斥量防止多个线程同时访问同一共享变量。条件变量允许一个线程就某个共享变量(或其他共享资源)的状态变化通知其他线程,并让其他线程等待(堵塞于)这一通知。
  • 代码区(顶)4 提供了一个例子。表明了主线程不停地循环检查变量avail的状态,故而造成了CPU资源的浪费。采用条件变量这一问题就解决了。允许一个线程休眠直至获得另一个线程的通知(收到信号)去执行某些操作。
  • 条件变量负责就共享变量的状态改变发出通知,而互斥量提供对该共享变量访问的互斥。

通知和等待条件变量

int pthread_cond_singal(pthread_cond_t *cond);

发出信号cond,使其他处于等待状态的线程唤醒。只保证唤醒至少一条遭到阻塞的线程。
注意:如果先发信号,而其他线程还未进入等待,是没有用的。
成功返回0,失败返回错误号。


int pthread_cond_broadcase(pthread_cond_t *cond);

发出信号cond,唤醒所有遭阻塞的线程。
成功返回0,失败返回错误号。

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

阻塞线程,等待信号。
成功返回0,失败返回错误号。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章