接着昨天的文章


  • 先回答上篇文章的问题:什么原因造成数据混乱?

首先计算靠的是 CPU,而CPU 的寄存器只能存储极少的数据,时时需要和内存交换。

这时 CPU 通过内存地址取值的时候,如果是操作的是共享资源(例如:全局变量),且进行多线程操作,如果某个线程的操作完后,还没有马上将数据放回内存,就失去了 CPU,那么在其他线程操作这个共享数据的时候,使用的还是旧值,数据自然就发生了混乱。

简单点一句话概括:你操作得太快了,其他人还没拿到最新的值,就去干活了。

  • 如何解决这个问题呢?

最主流的方法就是在操作共享数据前后添加 mutex 锁 (互斥锁)。

互斥锁

作用:

它用于防止多个线程同时访问共享资源。通过一种简单的加锁的方法来控制共享资源的访问, 互斥锁只有两种状态, 即lockunlock

特点:

  1. 原子性: 把一个互斥量锁定为一个原子操作,保证了如果一个线程锁定了一个互斥量,没有其他线程在同一时间可以成功锁定这个互斥量
  2. 唯一性:如果一个线程锁定了一个互斥量,在它解除锁定之前,没有其他线程可以锁定这个互斥量
  3. 非繁忙等待: 如果一个线程已经锁定了一个互斥量,第二个线程又试图去锁定这个互斥量,则第二个线程将被挂起(不占用任何 cpu 资源),直到第一个线程解除对这个互斥量的锁定为止,第二个线程则被唤醒并继续执行,同时锁定这个互斥量。

pthread_mutex_init

简述:初始化一个互斥锁,只要你调用了,就一定要初始化!

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

pthread_mutex_lock

简述:对互斥锁进行 lock,如果对已经上锁的资源进行调用,调用者会一直处于阻塞状态

  1. int pthread_mutex_lock(pthread_mutex_t *mutex);

pthread_mutex_unlock

简述:有 lock 就有它与 lock 对应,对互斥锁进行 unlock。

  1. int pthread_mutex_unlock(pthread_mutex_t *mutex);

pthread_mutex_destroy

简述:用完了锁记得销毁哦~ 为了释放资源

  1. int pthread_mutex_destroy(pthread_mutex_t *mutex);

这四个足以应付大部分的情况了。

pthread_mutex_trylock

简述:调用该函数时,若互斥锁未加锁,则上锁,返回 0,如果互斥锁已加锁,则函数直接返回失败 EBUSY

  1. int pthread_mutex_trylock(pthread_mutex_t *mutex);

改进昨天的代码

  1. #include <stdio.h>
  2. #include <pthread.h>
  3. #include <time.h>
  4. #include <windows.h>//使用Sleep的头
  5. int g_number = 0;
  6. #define MAX_COUNT 10000
  7. pthread_mutex_t mut;
  8. void *counter3(void* args) {
  9. int i = 1;
  10. while (i <= MAX_COUNT / 4) {
  11. pthread_mutex_lock(&mut);
  12. g_number++;
  13. pthread_mutex_unlock(&mut);
  14. printf("hi,i am pthread 3, my g_number is [%d]\n", g_number);
  15. Sleep(1);// 单位ms
  16. i++;
  17. }
  18. }
  19. void *counter4(void* args) {
  20. int j = 1;
  21. while (j <= MAX_COUNT / 4) {
  22. pthread_mutex_lock(&mut);
  23. g_number++;
  24. pthread_mutex_unlock(&mut);
  25. printf("hi,i am pthread 4, my g_number is [%d]\n", g_number);
  26. Sleep(1);
  27. j++;
  28. }
  29. }
  30. int main() {
  31. pthread_mutex_init(&mut, NULL);
  32. pthread_t t3;
  33. pthread_t t4;
  34. pthread_create(&t3, NULL, counter3, NULL);
  35. pthread_create(&t4, NULL, counter4, NULL);
  36. pthread_join(t3, NULL);
  37. pthread_join(t4, NULL);
  38. return 0;
  39. }

C语言多线程编程(二) - 知乎 - 图1

5000,程序正常!


修改了下代码规范问题,代码格式很重要!
https://zhuanlan.zhihu.com/p/97512154