• pthread条件变量


    pthread条件变量等待条件有两种方式:无条件等待pthread_cond_wait()和计时等待pthread_cond_timedwait(),其中计时等待方式如果在给定时刻前条件没有满足,则返回ETIMEOUT,结束等待,其中abstime以与time()系统调用相同意义的绝对时间形式出现,0表示格林尼治时间1970年1月1日0时0分0秒。  
       
     无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait()(或pthread_cond_timedwait())的竞争条件。mutex互斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)或者适应锁(PTHREAD_MUTEX_ADAPTIVE_NP),且在调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),而在更新条件等待队列以前,mutex保持锁定状态,并在线程挂起进入等待前解锁。在条件满足从而离开pthread_cond_wait()之前,mutex将被重新加锁,以与进入pthread_cond_wait()前的加锁动作对应。

     1 #include <pthread.h>
     2 #include <unistd.h>
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 
     6 static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
     7 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
     8  
     9 struct node {
    10     int n_number;
    11     struct node *n_next;
    12 } *head = NULL;
    13  
    14  // 线程清理函数
    15 static void cleanup_handler(void *arg)
    16 {
    17     printf("Cleanup handler of second thread.
    ");
    18     free(arg);
    19     (void)pthread_mutex_unlock(&mtx);
    20 }
    21 
    22 static void *thread_func(void *arg)
    23 {
    24     struct node *p = NULL;
    25  
    26     pthread_cleanup_push(cleanup_handler, p);
    27     while (true) {
    28         //这个mutex主要是用来保证pthread_cond_wait的并发性
    29         pthread_mutex_lock(&mtx);
    30 
    31         /*
    32         因为pthread_cond_wait里的线程可能会被意外唤醒,
    33         如果这个时候head != NULL,则不是我们想要的情况。
    34         这个时候,应该让线程继续进入pthread_cond_wait
    35         */
    36         while (head == NULL) {                     
    37             /*
    38             pthread_cond_wait会先解除之前的pthread_mutex_lock锁定的mtx,
    39             然后阻塞在等待对列里休眠,直到再次被唤醒(大多数情况下是等待的条件成立而被唤醒,
    40             唤醒后,该进程会先锁定先pthread_mutex_lock(&mtx);再读取资源                 
    41             用这个流程是比较清楚的block-->unlock-->wait() return-->lock
    42             */
    43             pthread_cond_wait(&cond, &mtx);  
    44         }
    45         p = head;
    46         head = head->n_next;
    47         printf("Got %d from front of queue
    ", p->n_number);
    48         free(p);
    49         //临界区数据操作完毕,释放互斥锁
    50         pthread_mutex_unlock(&mtx);
    51     }
    52     pthread_cleanup_pop(0);
    53     return 0;
    54 }
    55  
    56 int main(void)
    57 {
    58     pthread_t tid;
    59     int i;
    60     struct node *p;
    61     pthread_create(&tid, NULL, thread_func, NULL); 
    62 
    63     for (i = 0; i < 3; i++) {
    64         p = (struct node*)malloc(sizeof(struct node));
    65         p->n_number = i;
    66 
    67         // 加锁->signal->解锁
    68         pthread_mutex_lock(&mtx);
    69         p->n_next = head;
    70         head = p;
    71         pthread_cond_signal(&cond);
    72         pthread_mutex_unlock(&mtx);
    73         sleep(1);
    74     }
    75     printf("cancel thread
    ");
    76     /*
    77     从外部终止子线程,子线程会在最近的取消点,退出线程
    78     最近的取消点肯定就是pthread_cond_wait()了。
    79     */
    80     pthread_cancel(tid);
    81     // 等待cancel完成,不然可能不会执行到cleanup。
    82     pthread_join(tid, NULL);
    83     printf("All done -- exiting
    ");
    84     return 0;
    85 }

    pthread_cleanup_push来注册清理函数rtn,这个函数有一个参数arg。在以下三种情形之一发生时,注册的清理函数被执行:
        1)调用pthread_exit。
        2)作为对取消线程请求(pthread_cancel)的响应。
        3)以非0参数调用pthread_cleanup_pop。
    注意:
        1)如果线程只是由于简单的返回而终止的,则清除函数不会被调用。
        2)如果pthread_cleanup_pop被传递0参数,则清除函数不会被调用,但是会清除处于栈顶的清理函数。

  • 相关阅读:
    sql server中的 SET NOCOUNT ON 的含义
    SQL Server 中的嵌套事务与@@TranCount(转)
    数据库中的主键与外键的关系,通俗易懂
    模板制作
    DELPHI中MDI子窗口的关闭和打开
    Entity Framework 基础
    WPF使用HierarchicalDataTemplate绑定Dictionary生成TreeView
    WPF新手之如何将数据绑定到TreeView
    WPF数据验证(5)―― 错误模板
    WPF DataGrid 获取选中 一行 或者 多行
  • 原文地址:https://www.cnblogs.com/linyx/p/9709578.html
Copyright © 2020-2023  润新知