zoukankan      html  css  js  c++  java
  • phread_con_wait和pthread_mutex_lock实现的生产者消费者模型

    条件变量是利用线程间共享的全局变量进行同步的一种机制,

    主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;

    另一个线程使"条件成立"(给出条件成立信号)。

    为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。

    int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
    int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
    等待条件有两种方式:条件等待pthread_cond_wait()和计时等待pthread_cond_timedwait(),
    其中计时等待方式如果在给定时刻前条件没有满足,则返回ETIMEOUT,结束等待,
    其中abstime以与time()系统调用相同意义的绝对时间形式出现,0表示格林尼治时间1970年1月1日0时0分0秒。
    无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait()
    (或pthread_cond_timedwait(),下同)的竞争条件(Race Condition)。mutex互斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)
    或者适应锁(PTHREAD_MUTEX_ADAPTIVE_NP),且在调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),
    而在更新条件等待队列以前,mutex保持锁定状态,并在线程挂起进入等待前解锁。在条件满足从而离开pthread_cond_wait()之前,
    mutex将被重新加锁,以与进入pthread_cond_wait()前的加锁动作对应。
    激发条件有两种形式,pthread_cond_signal()激活一个等待该条件的线程,存在多个等待线程时按入队顺序激活其中一个;
    而pthread_cond_broadcast()则激活所有等待线程。
     
    现在来看一段典型的应用:看注释即可
      1 #include<pthread.h>
      2 #include<unistd.h>
      3 #include<stdio.h>
      4 #include<string.h>
      5 #include<stdlib.h>
      6 
      7 static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
      8 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
      9 
     10 struct node
     11 {
     12     int n_number;
     13     struct node*n_next;
     14 }*head = NULL;/*[thread_func]*/
     15 
     16 /*释放节点内存*/
     17 static void cleanup_handler(void*arg)
     18 {
     19     printf("Cleanup handler of second thread.
    ");
     20 
     21     struct node *p = *((struct node**)arg);
     22     while(p)
     23     {
     24         struct node* tmp = p->n_next;
     25         free(p);
     26         printf("free %p
    ", p);
     27         p = tmp;
     28     }
     29 
     30     *((struct node **)arg) = NULL;
     31 
     32     (void)pthread_mutex_unlock(&mtx);
     33 }
     34 
     35 static void* thread_func(void*arg)
     36 {
     37     struct node* p = NULL;
     38     pthread_cleanup_push(cleanup_handler, &head);
     39 
     40     while(1)
     41     {
     42         pthread_mutex_lock(&mtx);
     43         //这个mutex_lock主要是用来保护wait等待临界时期的情况,
     44         //当在wait为放入队列时,这时,已经存在Head条件等待激活
     45         //的条件,此时可能会漏掉这种处理
     46         //这个while要特别说明一下,单个pthread_cond_wait功能很完善,
     47         //为何这里要有一个while(head==NULL)呢?因为pthread_cond_wait
     48         //里的线程可能会被意外唤醒,如果这个时候head!=NULL,
     49         //则不是我们想要的情况。这个时候,
     50         //应该让线程继续进入pthread_cond_wait
     51 
     52         while(1)
     53         {
     54             while(head==NULL)
     55             {
     56                 pthread_cond_wait(&cond,&mtx);
     57             }
     58             //pthread_cond_wait会先解除之前的pthread_mutex_lock锁定的mtx,
     59             //然后阻塞在等待队列里休眠,直到再次被唤醒
     60             //(大多数情况下是等待的条件成立而被唤醒,唤醒后,
     61             //该进程会先锁定先pthread_mutex_lock(&mtx);,
     62             //再读取资源用这个流程是比较清楚的
     63             /*block-->unlock-->wait()return-->lock*/
     64 
     65             p = head;
     66             head = head->n_next;
     67             printf("Got %d from front of queue
    ",p->n_number);
     68             free(p);
     69         }
     70         pthread_mutex_unlock(&mtx);//临界区数据操作完毕,释放互斥锁
     71 
     72     }
     73 
     74     pthread_cleanup_pop(0);
     75 
     76     return 0;
     77 }
     78 
     79 int main(void)
     80 {
     81     pthread_t tid;
     82     int i;
     83     struct node* p;
     84     pthread_create(&tid,NULL,thread_func,NULL);
     85     //子线程会一直等待资源,类似生产者和消费者,
     86     //但是这里的消费者可以是多个消费者,
     87     //而不仅仅支持普通的单个消费者,这个模型虽然简单,
     88     //但是很强大
     89     for(i=0;i<10;i++)
     90     {
     91         p=(struct node*)malloc(sizeof(struct node));
     92         p->n_number=i;
     93         pthread_mutex_lock(&mtx);//需要操作head这个临界资源,先加锁,
     94         p->n_next=head;
     95         head=p;
     96         pthread_cond_signal(&cond);
     97         pthread_mutex_unlock(&mtx);//解锁
     98         sleep(1);
     99     }
    100 
    101     p=(struct node*)malloc(sizeof(struct node));
    102     p->n_number=i;
    103     pthread_mutex_lock(&mtx);//需要操作head这个临界资源,先加锁,
    104     p->n_next=head;
    105     head=p;
    106     pthread_mutex_unlock(&mtx);//解锁
    107 
    108     printf("thread1 wanna end the cancel thread2.
    ");
    109     pthread_cancel(tid);
    110     //关于pthread_cancel,有一点额外的说明,它是从外部终止子线程,
    111     //子线程会在最近的取消点,退出线程,而在我们的代码里,最近的
    112     //取消点肯定就是pthread_cond_wait()了。
    113     pthread_join(tid,NULL);
    114 
    115     printf("All done--exiting
    ");
    116 
    117     return 0;
    118 }
  • 相关阅读:
    Exchange 2013与 Office Web Apps 整合
    SharePoint2013 以其他用户登录和修改AD域用户密码 功能
    sharepoint 2010 自定义页面布局
    sharepoint 2010 记录管理 对象模型
    SharePoint2010 对象模型 关联列表
    在SharePoint Server 2010中更改“我的网站”
    xenapp 6.5 客户端插件第一次安装总是跳到官网
    如何解决在Windows Server 2008 R2 上安装证书服务重启后出现 CertificationAuthority 91错误事件
    在Win7 Hyper-v虚拟机中挂接真实机的声卡
    win8 中如何删除 共享文件夹 用户名和密码
  • 原文地址:https://www.cnblogs.com/jojodru/p/4022204.html
Copyright © 2011-2022 走看看