pthread_mutex_t & pthread_cond_t 总结( 二 )


第一种方法仅局限于静态初始化的时候使用:将「声明、定义、初始化」一气呵成,除此之外的情况都只能使用 pthread_mutex_init函数 。
2.2 pthread_mutex_init函数原型:int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
头  文  件:#include <pthread.h>
返  回  值:成功返回 0,失败返回错误码
参数介绍:
  1. mutex:指向 pthread_mutex_t 声明的变量的地址
  2. attr:指定了新建互斥锁的属性 。一般置为 NULL(如果参数attr为 NULL,则使用默认的互斥锁属性,默认属性为快速互斥锁 ) 。
restrict 关键字只用于限制指针 。告诉编译器所有修改该指针指向内存中的操作,只能通过本指针完成,不能通过除了本指针之外的变量或指针修改 。
当我们通过 pthread_mutex_init() 初始化互斥量后,接下来就是上锁(pthread_mutex_lock)和解锁(pthread_mutex_unlock)操作了 。
2.3 上锁 & 解锁
上锁解锁函数原型pthread_mutex_lock(pthread_mutex_t *mutex);int pthread_mutex_unlock(pthread_mutex_t *mutex);头  文  件#include <pthread.h>#include <pthread.h>返  回  值成功返回 0,失败返回错误码成功返回 0,失败返回错误码让我们来梳理一下互斥量的使用流程:
  1. 通过 pthread_mutex_init() 购买一把锁
  2. 通过 pthread_mutex_lock() 加锁
  3. 通过 pthread_mutex_unlock() 解锁
下面让我们通过「锁」操作修改一下上述代码:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 静态初始化锁void *func1(void *arg){    pthread_mutex_lock(&mutex);    puts("线程 th1 抢到锁");    puts("线程 th1 开始执行 giNum++");    int i;    for (i = 1; i <= MAX; i++)    {        giNum++;    }    pthread_mutex_unlock(&mutex);    return NULL;}void *func2(void *arg){    pthread_mutex_lock(&mutex);    puts("线程 th2 抢到锁");    puts("开始执行 giNum++");    int i;    for (i = 1; i <= MAX; i++)    {        giNum *= 2;    }    pthread_mutex_unlock(&mutex);    return NULL;}此时,再次运行程序,你会发现不管运行多少次,结果都是 \(giNum = 2\times10^7\) 。
下面我们对上面的代码做个简单的修改,将 func2 中的giNum++操作修改为giNum *= 2,
三、条件变量3.1 为什么要使用条件变量如果没有条件变量,那么我们等待一个条件满足则会是下面这样的模型:
pthread_mutex_t &amp; pthread_cond_t 总结

文章插图
  • 首先加锁进入临界区去查看条件是否满足,不满足则解锁离开临界区,睡眠一段时间再继续循环判断 。
在这种情况下如果刚离开临界区,条件变为满足,那么线程必须还要等一段时间重新进入临界区才能知道条件满足(如果在这段时间内,条件依旧一直保持满足的话);如果这一小段时间条件又变为了不满足,那么这个线程还要继续循环判断,不断地加锁解锁(会影响使用同一把锁的其他线程),还不能第一时间收到条件满足 。

经验总结扩展阅读