互斥量的使用

只有所有线程都遵循相同的数据访问规则的时候,锁机制才生效。
互斥量是一把锁,常见的操作有:

  1. // 进行加锁,如果加锁失败,进程被阻塞
  2. int pthread_mutex_lock(pthread_mutex_t *mutex);
  3. // 尝试进行加锁。如果加锁成功,返回0;如果加锁失败,进程不会被阻塞,返回 EBUSY
  4. int pthread_mutex_trylock(pthread_mutex_t *mutex);
  5. // 进行解锁
  6. int pthread_mutex_unlock(pthread_mutex_t *mutex);

加锁失败的线程会陷入阻塞。获得锁的线程释放锁后,阻塞的所有线程都会被唤醒,然后尝试获取锁,获取失败的线程再度阻塞。

在使用互斥量之前,需要先进行初始化,使用完之后,要销毁互斥量。

  1. // 初始化互斥量
  2. int pthread_mutex_init(phtread_mutex_t *mutex, const pthread_mutexattr_t *attr);
  3. // 销毁互斥量
  4. int pthread_mutex_destroy(pthread_mutex_t *mutex);

使用的例子:

  1. #include <pthread.h>
  2. #include <unistd.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. pthread_mutex_t g_mutex1; // 全局互斥量
  6. int g_num; // 全局变量
  7. void *thr_fn1(void *args)
  8. {
  9. pthread_mutex_lock(&g_mutex1);
  10. g_num += 2;
  11. printf("[thread_1]g_num: %d\n", g_num);
  12. pthread_mutex_unlock(&g_mutex1);
  13. return (void *)0;
  14. }
  15. void *thr_fn2(void *args)
  16. {
  17. pthread_mutex_lock(&g_mutex1);
  18. g_num += 3;
  19. printf("[thread_2]g_num: %d\n", g_num);
  20. pthread_mutex_unlock(&g_mutex1);
  21. return (void *)0;
  22. }
  23. int main()
  24. {
  25. void *rval; // 线程的返回值
  26. pthread_t tid1, tid2;
  27. // 初始化互斥量
  28. pthread_mutex_init(&g_mutex1, NULL);
  29. // 创建线程
  30. (void)pthread_create(&tid1, NULL, thr_fn1, NULL);
  31. (void)pthread_create(&tid2, NULL, thr_fn2, NULL);
  32. // 回收线程
  33. pthread_join(tid1, &rval);
  34. pthread_join(tid2, &rval);
  35. // 销毁互斥量
  36. pthread_mutex_destroy(&g_mutex1);
  37. exit(0);
  38. }

死锁

死锁情形1:一个线程对同一个互斥量加两次锁:

  1. void *thr_fun1(void *args)
  2. {
  3. pthread_mutex_lock(&g_mutex1);
  4. pthread_mutex_lock(&g_mutex2);
  5. // 陷入死锁
  6. }

死锁情形2:如果一个线程需要对多个互斥量进行加锁,那么需要确保多个线程之间加锁顺序一致。

有锁就必定有箱子,锁的作用是保护箱子中的内容的。在使用锁的时候,需要明确这把锁保护的是什么东西,定义好。

等待超时