• Day57 Linux 条件变量 信息量


    目录

    1. 条件变量

    1.1主要应用函数

     1.2生产-消费者模型

    2. 信号量

     


    1. 条件变量

    条件变量本身不是锁 ! 但它也可以造成线程阻塞。
    通常与互斥锁配合使用。给多线程提供一个会合的场所。

    1.1主要应用函数

    pthread_cond_init 函数。
    pthread_cond_destroy 函数。
    pthread_cond_wait 函数。
    pthread_cond_timedwait 函数。
    pthread_cond_signal 函数。
    pthread_cond_broadcast 函数。
    pthread_cond_t 类型用于定义条件变量。
    pthread_cond_t cond;

    pthread_cond_init 函数  

    初始化一个条件变量。
    int pthread_cond_init ( pthread_cond_t * restrict cond ,
                                      const pthread_condattr * restrict attr );
    1 :需要初始化的条件变量
    2 : attr 表条件变量属性,通常为默认值,传 NULL 即可

    初始化有两种方法:

    1. 动态初始化: pthread_cond_init & cond NULL
    2. 静态初始化: pthread_cond_t cond = PTHREAD_COND_INITIALIZER ; 

    pthread_cond_wait 函数

    阻塞等待一一个条件变量

    int pthread_cond_wait ( pthread_cond_t * restrict cond ,
                                            pthread_mutex_t * restrict mutex );
    1 :已经初始化号的条件变量,如果条件不满足,则一直阻塞等待
    2 :一把已加锁的互斥锁,解锁已加锁的 mutex ,等价 pthread_mutex_unlock ( & mutex )
            参1 、参 2 执行时是原子操作。(也就阻塞时,会继续操作解锁,中途不会被中断)
    函数返回 return 前:
            当条件变量必须满足,同步解除阻塞并重新给互斥量加pthread_mutex_lock ( & mutex )

     

    pthread_cond_signal函数

    唤醒等待在该条件变量上的一个线程

    pthread_cond_broadcast函数

    唤醒等待在该条件变量上的所有线程

    int pthread_cond_signal ( & cond );
    1 :已经初始化好的条件变量

     1.2生产-消费者模型

    例程:生产-消费者模型代码

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. /*链表作为公享数据,需被互斥量保护*/
    7. #define SIZE 100
    8. int repository[SIZE]={0};//定义仓库大小,并初始化为0
    9. /*静态初始化一个条件变量和一个互斥量*/
    10. pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
    11. pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
    12. int empty_repository(int arr[])
    13. {
    14. int i,sum=0;
    15. for(i=0;i
    16. {
    17. sum += arr[i];
    18. }
    19. return sum;
    20. }
    21. int fill_repository(int arr[])
    22. {
    23. int i,sum;
    24. for(i=0;i
    25. {
    26. if(arr[i]==0)
    27. {
    28. arr[i]= rand() % 1000 + 1;
    29. printf("-------fill a[%d]=%d\n",i,arr[i]);
    30. return arr[i];
    31. }
    32. }
    33. return -1;
    34. }
    35. int del_repository(int arr[])
    36. {
    37. int i,temp;
    38. for(i=SIZE;i>=0;i--)
    39. {
    40. if(arr[i]!=0)
    41. {
    42. temp=arr[i];
    43. printf("-------del a[%d]=%d\n",i,arr[i]);
    44. arr[i]= 0;
    45. return temp;
    46. }
    47. }
    48. return -1;
    49. }
    50. void *consumer(void *p)
    51. {
    52. for (;;)
    53. {
    54. int ret=pthread_mutex_lock(&lock);
    55. if(ret !=0)
    56. {
    57. printf("consumer mutex_lock err:%s\n",strerror(ret));
    58. }
    59. while (!empty_repository(repository))
    60. {
    61. //如果条件不满足,释放锁,并阻塞在此处
    62. //如果条件满足,重新加锁,并解除阻塞,进行循环条件判断
    63. printf("cond_wait test mask\n");
    64. pthread_cond_wait(&has_product, &lock);
    65. }
    66. //模拟消费掉一个产品
    67. ret=del_repository(repository);
    68. if(ret==-1)
    69. {
    70. printf("del_repository() err\n");
    71. pthread_exit(NULL);
    72. }
    73. pthread_mutex_unlock(&lock);
    74. printf("-Consume %lu---Produce id=%d\n", pthread_self(), ret);
    75. sleep(rand() % 5);
    76. }
    77. }
    78. void *producer(void *p)
    79. {
    80. for (; ;)
    81. { //sleep(5),为验证consumer线程中的,pthread_cond_wait()会进行解锁+阻塞功能
    82. sleep(5);
    83. //生产者拿锁成功,再生产产品
    84. int ret=pthread_mutex_lock(&lock);
    85. if(ret !=0)
    86. {
    87. printf("producer mutex_lock() err:%s\n",strerror(ret));
    88. pthread_mutex_unlock(&lock);
    89. break;//跳出循环
    90. }
    91. //模拟生产一个产品
    92. ret=fill_repository(repository);
    93. if(ret==-1)
    94. {
    95. printf("fill_repository() err\n");
    96. pthread_mutex_unlock(&lock);
    97. break;
    98. // pthread_exit(NULL);//生产仓库满后,无法继续生产,退出生产线程
    99. }
    100. pthread_mutex_unlock(&lock);
    101. printf("-producer %lu---Produce id=%d\n", pthread_self(), ret);
    102. pthread_cond_signal(&has_product); //条件满足了,通知等待条件变量has_product的线程
    103. usleep(100000);
    104. }
    105. }
    106. int main(int argc, char *argv[])
    107. {
    108. pthread_t tid01, tid02,tid03;
    109. srand(time(NULL));
    110. pthread_create(&tid01, NULL, producer, NULL);
    111. pthread_create(&tid02, NULL, consumer, NULL);
    112. // pthread_create(&tid03, NULL, consumer, NULL);
    113. pthread_join(tid01, NULL);
    114. pthread_join(tid02, NULL);
    115. // pthread_join(tid03, NULL);
    116. return 0;
    117. }

    2. 信号量

    信号量,是相对折中的一 - 种处理方式,既能保证同步,数据不混乱,又能提高线程并发。
    由于互斥锁的粒度比较大,如果我们希望在多个线程间对某一对象的部分数据进行共享,使用互斥锁是没有办法实现的,只能将整个数据对象锁住。这样虽然达到了多线程操作共享数据时保证数据正确性的目的,却无形中导致线程的并发性下降。线程从并行执行,变成了串行执行。与直接使用单进程无异。
    主要函数
    sem_init 函数
    sem_destroy 函数
    sem_wait 函数
    sem_trywait 函数
    sem_timedwait 函数
    sem_post 函数
    以上 6 个函数的返回值都是 : 成功返回 0 ,失败返回 -1 , 同时设置 errno ( 注意,它们没有 pthread 前缀 )
    sem_t 类型 , 本质仍是结构体。但应用期间可简单看作为整数,忽略实现细节 ( 类似于使用文件描述符 )
    sem_tsem; 规定信号量 sem 不能 <0 头文件

    信号量基本操作
    sem_wait: 1. 信号量大于 0 ,则信号量 -- ( 类比 pthread_mutex_lock)
                    2.信号量等于0 时,再次调用会造成线程阻塞。
    对应
    sem_post : 将信号量 ++ ,同时唤醒阻塞在信号量上的线程 ( 类比 pthread_mutex_unlock)
    但,由于 sem 的实现对用户隐藏,所以所谓的 ++. -- 操作只能通过函数来实现,而不能直接 ++ - 符号信号量的初值,决定了占用信号量的线程的个数。
    sem_init 函数
    初始化信号量
    int sem_init ( sem_t * sem , int pshared , unsigned int vale )
    1 sem 已定义的信号量
    2 pshared 0 用于线程间同步
                            1 用于进程间同步
    3 vale N 值,指定同时能够访问的线程数
    sem_destroy 函数
    销毁信号量

     int sen_destroy(sem_t *sem);

    sem_wait 函数
    信号量减减操作 ( 类似加锁 )
    int sem_wait ( sen_t * sem );
    sem_post 函数
    信号量加加操作 ( 类似解锁 )
    int sem_post ( sen_t * sem );

    sem_timedwait 函数

    限时尝试对信号量加锁

    int sem_timedwait ( sem_t * sem , const struct timespec * abs_timeout );
    2 : abs_timeout 采用的是绝对时间( 1970 1 1 0 0 0 秒)。
    比如定时 1 :
    time_t cur = time ( NULL ); 获取当前时间
    struct timespec t ; 定义 timespec 结构体变量 t
    t . tv_sec = cur + 1 ; 定时 1 秒。
    t . tv_nsec = t . tv_sec + 100 ;
    sem_timedwait ( & sem , & t ); 传参

     

     

     

     

     

     

     

  • 相关阅读:
    基于遗传算法的水力发电厂的优化(Matlab代码实现)
    Esbuild Bundler HMR
    网络协议--TCP连接的建立与终止
    流程自动化(RPA)的好处有哪些?
    NumPy简单学习(需要结合书本)
    Caldera(二)高级实战
    Jupyter Notebook快速上手
    开发小程序插件如何实现盈利?
    Java刷题时常用的标准库数据结构和相应操作
    满级大牛 HuaWei 首次出这份 598 页【网络协议全彩手册】,建议大家收藏
  • 原文地址:https://blog.csdn.net/qq_59947178/article/details/127656787