Linux系统编程之线程同步处理(互斥量和条件变量)

每个线程都能够单独执行一个命令,当创建多条线程并且多线程同时会对全局变量(同一文件)等进行调用, 这时就要注意同步处理了,不然可能会出现超出你预料的变化, 这是因为CUP的调度是随机的而引起的。

线程中有一种专门处理这种问题的方法, 称之为互斥量, 它能确保同时仅有一个线程可以访问一个共享资源, 这能保证其对任意共享资源的原子访问。互斥量有锁定(lock)和未锁定(unlock)两种状态,最多只有一个线程可以锁定该互斥量。只有锁定该互斥量的线程可以进行解锁。

互斥量属于pthread_mutex_t类型的变量,函数原型:

#include<pthread.h>

int pthread_mutex_lock(pthread_mutex_t *mutex);  //阻塞

int pthread_mutex_trylock(pthread_mutex_t *mutex); //非阻塞

int pthread_mutex_unlock(pthread_mutex_t *mutex);

返回0时表示成功

当调用pthread_mutex_unlock()时,如果互斥量当前未处于锁定状态, 则立即返回, 如果已经有其他线程锁定了这一互斥量, 则会一直堵塞,直至该互斥量被解锁。(如果同一线程在调用pthread_mutex_unlock()前已经调用了一次,那么会处于死锁状态, 所以在给一个互斥量上锁后, 一定要记得有解锁动作)。

互斥量性能

互斥量时比较高效的防止多线程抢占资源的一种方式, 较文件锁和信号量而言,互斥量只有在发生锁的征用时才会执行系统调用, 而文件锁和信号量在解锁和加锁时总是会发起系统调用。

有时为了提高效率, 多个线程对一组互斥量进行操作时, 为了避免死锁情况, 可以设置互斥量的层级关系。


互斥量有两种分配方式, 静态分配和动态分配。

静态分配:pthread_mutex_t max = PTHREAD_MUTEX_INITIALIZER;

动态分配:(如malloc()在一块内存种分配),这时需要进行动态初始化--》pthread_mutex_init(),无需使用时一定要摧毁,

                   pthread_mutex_destroy();

   函数原型

#include<pthread.h>

int pthread_mutex_init(pthread_mutex_t  *mutex, const pthread_mutexattr_t *attr);

int pthread_mutex_destroy(pthread_mutex_t  *mutex);

返回0成功;

参数:

mutex:目标互斥量;

attr:互斥量的属性,为NULL时,会取默认值。

互斥量类型

PTHREAD_MUTEX_NORMAL(该类型的互斥量不具有死锁检测(自检)功能);

PTHREAD_MUTEX_ERRORCHECK(所有操作都会执行错误检查, 这一类执行比一般要慢很多,通常用于debug);

PTHRAD_MUTEX_RECURESIVE(递归互斥量维护有一个锁计数器);

以下是一个简单设置互斥量类型的例子:

pthread_mutex_t mtx;
       pthread_mutexattr_t mtxattr;

int s, type;

s = pthread_mutexattr_init(&mtxattr);
       if(s != 0){
         printf("pthread_mutexattr_init error\n");
         return -1;
       }

s = pthread_mutexattr_settype(&mtxattr, PTHREAD_MUTEX_ERRORCHECK);
       if(s != 0){
         printf("pthread_mutexattr_settype error\n");
         return -1;
      }

if(pthread_mutex_init(&mutex, &mtxattr) != 0){
         printf("pthread_mutex_init error\n");
         return -1;
     }

pthread_mutex_destroy(&mutex);


互斥量防止多个线程同时访问同一个共享变量。条件变量则允许一个线程就某一个共享变量的状态变化通知其他线程, 并且让其他线程等待(堵塞)这已通知。条件变量这一特性无疑会大大提高CPU性能,所以互斥量和条件变量总是互相结合使用。条件变量就共享变量的状态改变发出通知, 而互斥量则提供对该共享变量访问的互斥。

条件变量与互斥量初始化基本一制

静态分配:pthread_cont_t  cond = PTHREAD_CONT_INITIALIZER;

动态分配:

#include<pthread.h>

int pthread_cont_init(pthread_count_t  *cond, const pthread_condattr_t *attr);

int pthread_cond_destroy(pthread_cond_t  *cond);

返回0成功;

参数:

cond:目标条件变量;

attr:条件变量的属性,为NULL时,会取默认值。

条件变量相关API:

#include<pthread.h>

int pthread_cond_signal(pthread_cond_t *cond);

int pthread_cond_broadcast(pthread_cond_t *cond);

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

int pthread_cond_timewait(pthread_cond_t *cond, pthread_mutex_t *mutex,

                                         const  struct timespec *abstime);

返回0 成功;

条件变量主要操作就是发送信号和等待。pthread_cond_signal()和pthread_cond_broadcast()都可发送信号。pthread_cond_wait()和pthread_cond_timewait()将阻塞一线程,直到收到条件变量cond的通知。

注意

pthread_cond_signal()和pthread_cond_broadcast()的区别在于阻塞与pthread_cond_wait()的 多个线程处理方式不同。pthread_cond_signal()只会唤醒一条阻塞的等待种的线程, 而pthread_cond_broadcast()会通知所有阻塞等待的线程。

pthread_cond_wait()和pthread_cond_timewait()的区别则在于参数abstime 可以指定一个线程等待条件变量通知时的休眠(阻塞)时间上限。

Guess you like

Origin blog.csdn.net/huang422600/article/details/103545002