同步

线程同步—协同步调,有先后的运行次序,保证数据一致性。

出现与时间有关的错误,需要使用同步机制:

  • 数据共享
  • 竞争
  • 多个对象访问

锁不具有强制性,非“君子”的线程仍然可以访问。Linux中都是建议锁,不具有强制性

互斥量/互斥锁

初始化后初值为1 !!!

  1. pthread_mutex_t
  2. pthread_mutex_init(&mutex,NULL);//mutex -> 1
  3. **restrict关键字限制不能通过除了本指针以外的其他变量或指针修改
  4. pthread_mutex_lock(&mutex);
  5. //deal......
  6. pthread_mutex_unlock(&mutex);
  7. pthread_mutex_destroy(&mutex);

访问共享数据前加锁,访问结束后立即解锁,使锁的粒度尽可能小

死锁

  • 线程试图对同一互斥量加锁两次,加锁第二次阻塞,无限等待
  • 两个数据,两把锁,两个进程;TI有A锁请求B锁,T2有B锁请求A锁;同时阻塞

解决方法:

获取所有需要的锁失败,主动放弃已有的锁

DEMO模拟实现死锁现象

读写锁

和互斥量类似,效率较高,写独占,读共享,写锁(抢占过程中)优先级高

一把锁具备三种状态:读锁 写锁 不加锁

  1. pthread_rwlock_t
  2. pthread_rwlock_init
  3. pthread_rwlock_destroy
  4. //rdlock wrlock tryrdlock(非阻塞) trywrlock unlock

条件变量

条件变量本身不是锁,条件变量是描述一个条件,但是可以让进程阻塞,和互斥锁配合使用。

  1. pthread_cond_init
  2. pthread_cond_destroy
  3. pthread_cond_wait //阻塞等待一个条件变量
  4. //参数需要一把互斥锁
  5. pthread_cond_timedwait//阻塞设定时常
  6. pthread_cond_signal//唤醒一个阻塞在条件变量上的线程
  7. pthread_cond_broadcast//唤醒至少一个阻塞在条件变量上的线程

pthread_cond_wait

  1. 阻塞等待条件变量
  2. 释放已掌握的互斥锁
  3. 1,2为原子操作
  4. 等待唤醒,pthread_cond_wait返回时 解除阻塞 重新申请加锁

pthread_timed_wait

  1. struct timespec* abs_time;//绝对时间 1970-01-01 00:00:00
  2. // s ns
  3. // 初始化用法
  4. time_t cur = time(NULL);
  5. struct timespec t;
  6. t.tv_sec = cur+1;
  7. //然后传参
  8. //timeval s ms

条件变量的优点

减小消费者的竞争,提高程序效率

生产者消费者条件变量模型

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<unistd.h>
  4. #include<pthread.h>
  5. #include<string.h>
  6. pthread_mutex_t mutex;
  7. pthread_cond_t cond;
  8. int product = 0;
  9. void* produce(void* arg)
  10. {
  11. int i=50;
  12. while(i--)
  13. {
  14. pthread_mutex_lock(&mutex);
  15. pthread_mutex_unlock(&mutex);
  16. printf("produce: %d\n",++product);
  17. pthread_cond_signal(&cond);
  18. sleep(3);
  19. }
  20. }
  21. void* consume(void* arg)
  22. {
  23. int i=10;
  24. while(i--)
  25. {
  26. pthread_mutex_lock(&mutex);
  27. while(product==0)//惊群效应
  28. pthread_cond_wait(&cond,&mutex);
  29. printf("consume: %d\n",--product);
  30. pthread_mutex_unlock(&mutex);
  31. sleep(2);
  32. }
  33. }
  34. int main()
  35. {
  36. pthread_mutex_init(&mutex,NULL);
  37. pthread_cond_init(&cond,NULL);
  38. pthread_t tid[6];
  39. for(int i=0;i<5;i++)
  40. {
  41. pthread_create(&tid[i],NULL,consume,NULL);
  42. }
  43. pthread_create(&tid[5],NULL,produce,NULL);
  44. for(int i=0;i<6;i++)
  45. pthread_join(tid[i],NULL);
  46. pthread_mutex_destroy(&mutex);
  47. pthread_cond_destroy(&cond);
  48. return 0;
  49. }

信号量(互斥量升级版 多个线程)

线程进程通用

  1. sem_t // 0~n
  2. sem_init //设置是否在进程间共享 --信号量初值 决定信号量的线程个数--
  3. sem_destroy
  4. sem_trywait
  5. sem_wait //信号量-- 0阻塞
  6. sem_timedwait
  7. sem_post //信号量++

生产者消费者 信号量 模型

  1. //两个信号量 产品数 剩余空间数

进程间同步方法

  • 信号量
  • 互斥量(修改属性为进程间共享)
  1. pthread_mutexattr_init
  2. pthread_mutex_setpshared
  3. PTHREAD_PROCESS_PRIVATE
  4. PTHREAD_PROCESS_SHARED//进程
  • 文件锁(fcntl)
  1. F_SETLK//设置文件锁 非阻塞
  2. F_SETLKW//设置文件锁 阻塞
  3. //加锁解锁宏相同 通过flock结构体控制
  4. F_GETLK//获取文件锁
  5. struct flock{
  6. l_type 读锁解锁写锁
  7. whence偏移位置 SEEK_SET CUR END
  8. start起始偏移 从偏移位置开始
  9. len0锁整个文件
  10. pid F_GETLKONLY
  11. }

多线程无法使用文件锁,可以使用读写锁

DEMO哲学家就餐问题 线程版 进程版