pthread_mutex_t & pthread_cond_t 总结

pthread_mutex_t & pthread_cond_t 总结一、多线程并发1.1 多线程并发引起的问题我们先来看如下代码:
#include <stdio.h>#include <pthread.h>#include <unistd.h>#define MAX 1E7int giNum = 0;void *func1(void *arg){    int i;    for (i = 1; i <= MAX; i++)    {        giNum++;    }    return NULL;}void *func2(void *arg){    int i;    for (i = 1; i <= MAX; i++)    {        giNum++;    }    return NULL;}int main(){    pthread_t th1;    pthread_create(&th1, NULL, func1, NULL);    pthread_t th2;    pthread_create(&th2, NULL, func2, NULL);    pthread_join(th1, NULL);    pthread_join(th2, NULL);    printf("giNum = %d\n", giNum);    return 0;}代码的内容很简单:

  1. 创建了两个子线程 th1、th2
  2. 两个子线程分别执行giNum++操作
  3. 最后输出giNum的值
直观地看过去:
  • th1 运行时giNum++要执行 \(10^7\) 次
  • th2 运行时giNum++也要执行 \(10^7\) 次
似乎计算得到的最后 giNum 应该是 \(2\times10^7\) 。但实际上是这样的吗?让我们来看一下运行结果:
pthread_mutex_t &amp; pthread_cond_t 总结

文章插图
多次运行,你会发现,仅有一次(甚至没有)结果是正确的 。
1.2 知根知底上述代码得到的结果为什么不如顺序执行所预期的那样呢?可以用程序修改变量值时所经历的三个步骤解释这个现象:
  • 从内存单元读入寄存器
  • 在寄存器中对变量操作(加/减1)
  • 把新值写回到内存单元
即当我们当我们执行giNum++时,底层发生的事件其实是:
  1. 内存中读取 giNum;
  2. 将 giNum++;
  3. 将 giNum 写入到内存 。
这不是一个原子化操作,当两个线程交错运行的时候,很容易发生结果的丢失 。因此最后的结果肯定是要 \(\leq 2\times10^7\) 的 。这种情况有种专有名词,叫 race condition 。为了解决这个问题,我们可以「加锁」 。
二、线程锁2.1 互斥量多线程程序中可能会存在数据不一致的情况,那么如何保证数据一致呢?可以考虑同一时间只有一个线程访问数据 。
而互斥量(mutex)就是一把锁 。多个线程只有一把锁一个钥匙,谁上的锁就只有谁能开锁 。当一个线程要访问一个共享变量时,先用锁把变量锁住,然后再操作,操作完了之后再释放掉锁;当另一个线程也要访问这个变量时,发现这个变量被锁住了,无法访问,它就会一直等待,直到锁没了,它再给这个变量上个锁,然后使用,使用完了释放锁,以此进行 。这样即使有多个线程同时访问这个变量,也好像是对这个变量的操作是顺序进行的 。
互斥变量使用特定的数据类型:pthread_mutex_t 。使用互斥量前要先初始化,初始化又分为静态初始化和动态初始化: