zoukankan      html  css  js  c++  java
  • Linux系统编程(29)——线程间同步(续篇)


    线程间的同步还有这样一种情况:线程A需要等某个条件成立才能继续往下执行,现在这个条件不成立,线程A就阻塞等待,而线程B在执行过程中使这个条件成立了,就唤醒线程A继续执行。在pthread库中通过条件变量(Condition Variable)来阻塞等待一个条件,或者唤醒等待这个条件的线程。Condition Variable用pthread_cond_t类型的变量表示,可以这样初始化和销毁:

    #include <pthread.h>

    int pthread_cond_destroy(pthread_cond_t*cond);

    int pthread_cond_init(pthread_cond_t*restrict cond,

          const pthread_condattr_t *restrict attr);

    pthread_cond_t cond =PTHREAD_COND_INITIALIZER;

    返回值:成功返回0,失败返回错误号。

    和Mutex的初始化和销毁类似,pthread_cond_init函数初始化一个Condition Variable,attr参数为NULL则表示缺省属性,pthread_cond_destroy函数销毁一个Condition Variable。如果Condition Variable是静态分配的,也可以用宏定义PTHEAD_COND_INITIALIZER初始化,相当于用pthread_cond_init函数初始化并且attr参数为NULL。ConditionVariable的操作可以用下列函数:

    #include <pthread.h>

    int pthread_cond_timedwait(pthread_cond_t*restrict cond,

          pthread_mutex_t *restrict mutex,

          const struct timespec *restrict abstime);

    int pthread_cond_wait(pthread_cond_t*restrict cond,

          pthread_mutex_t *restrict mutex);

    int pthread_cond_broadcast(pthread_cond_t*cond);

    int pthread_cond_signal(pthread_cond_t*cond);

    返回值:成功返回0,失败返回错误号。

    可见,一个Condition Variable总是和一个Mutex搭配使用的。一个线程可以调用pthread_cond_wait在一个Condition Variable上阻塞等待,这个函数做以下三步操作:

    1、释放Mutex

    2、阻塞等待

    3、当被唤醒时,重新获得Mutex并返回

    pthread_cond_timedwait函数还有一个额外的参数可以设定等待超时,如果到达了abstime所指定的时刻仍然没有别的线程来唤醒当前线程,就返回ETIMEDOUT。一个线程可以调用pthread_cond_signal唤醒在某个Condition Variable上等待的另一个线程,也可以调用pthread_cond_broadcast唤醒在这个Condition Variable上等待的所有线程。

    下面的程序演示了一个生产者-消费者的例子,生产者生产一个结构体串在链表的表头上,消费者从表头取走结构体。

    #include <stdlib.h>

    #include <pthread.h>

    #include <stdio.h>

    struct msg {

             structmsg *next;

             intnum;

    };

    struct msg *head;

    pthread_cond_t has_product =PTHREAD_COND_INITIALIZER;

    pthread_mutex_t lock =PTHREAD_MUTEX_INITIALIZER;

    void *consumer(void *p)

    {

             structmsg *mp;

             for(;;) {

                       pthread_mutex_lock(&lock);

                       while(head == NULL)

                                pthread_cond_wait(&has_product,&lock);

                       mp= head;

                       head= mp->next;

                       pthread_mutex_unlock(&lock);

                       printf("Consume%d ", mp->num);

                       free(mp);

                       sleep(rand()% 5);

             }

    }

    void *producer(void *p)

    {

             structmsg *mp;

             for(;;) {

                       mp= malloc(sizeof(struct msg));

                       mp->num= rand() % 1000 + 1;

                       printf("Produce%d ", mp->num);

                       pthread_mutex_lock(&lock);

                       mp->next= head;

                       head= mp;

                       pthread_mutex_unlock(&lock);

                       pthread_cond_signal(&has_product);

                       sleep(rand()% 5);

             }

    }

    int main(int argc, char *argv[])

    {

             pthread_tpid, cid; 

             srand(time(NULL));

             pthread_create(&pid,NULL, producer, NULL);

             pthread_create(&cid,NULL, consumer, NULL);

             pthread_join(pid,NULL);

             pthread_join(cid,NULL);

             return0;

    }执行结果如下:

    Produce 744

    Consume 744

    Produce 567

    Produce 881

    Consume 881

    Produce 911

    Consume 911

    Consume 567

    Produce 698

    Consume 698

    在这个例子中,生产者和消费者访问链表的顺序是LIFO的。

    Mutex变量是非0即1的,可看作一种资源的可用数量,初始化时Mutex是1,表示有一个可用资源,加锁时获得该资源,将Mutex减到0,表示不再有可用资源,解锁时释放该资源,将Mutex重新加到1,表示又有了一个可用资源。

    信号量(Semaphore)和Mutex类似,表示可用资源的数量,和Mutex不同的是这个数量可以大于1。

    这里介绍的是POSIX semaphore库函数,详见sem_overview(7),这种信号量不仅可用于同一进程的线程间同步,也可用于不同进程间的同步。

    #include <semaphore.h>

    int sem_init(sem_t *sem, int pshared,unsigned int value);

    int sem_wait(sem_t *sem);

    int sem_trywait(sem_t *sem);

    int sem_post(sem_t * sem);

    int sem_destroy(sem_t * sem);

    semaphore变量的类型为sem_t,sem_init()初始化一个semaphore变量,value参数表示可用资源的数量,pshared参数为0表示信号量用于同一进程的线程间同步,本节只介绍这种情况。在用完semaphore变量之后应该调用sem_destroy()释放与semaphore相关的资源。

    调用sem_wait()可以获得资源,使semaphore的值减1,如果调用sem_wait()时semaphore的值已经是0,则挂起等待。如果不希望挂起等待,可以调用sem_trywait()。调用sem_post()可以释放资源,使semaphore的值加1,同时唤醒挂起等待的线程。

    上面生产者-消费者的例子是基于链表的,其空间可以动态分配,现在基于固定大小的环形队列重写这个程序:

    #include <stdlib.h>

    #include <pthread.h>

    #include <stdio.h>

    #include <semaphore.h>

    #define NUM 5

    int queue[NUM];

    sem_t blank_number, product_number;

    void *producer(void *arg)

    {

             intp = 0;

             while(1) {

                       sem_wait(&blank_number);

                       queue[p]= rand() % 1000 + 1;

                       printf("Produce%d ", queue[p]);

                       sem_post(&product_number);

                       p= (p+1)%NUM;

                       sleep(rand()%5);

             }

    }

    void *consumer(void *arg)

    {

             intc = 0;

             while(1) {

                       sem_wait(&product_number);

                       printf("Consume%d ", queue[c]);

                       queue[c]= 0;

                       sem_post(&blank_number);

                       c= (c+1)%NUM;

                       sleep(rand()%5);

             }

    }

    int main(int argc, char *argv[])

    {

             pthread_tpid, cid; 

             sem_init(&blank_number,0, NUM);

             sem_init(&product_number,0, 0);

             pthread_create(&pid,NULL, producer, NULL);

             pthread_create(&cid,NULL, consumer, NULL);

             pthread_join(pid,NULL);

             pthread_join(cid,NULL);

             sem_destroy(&blank_number);

             sem_destroy(&product_number);

             return0;

    }

  • 相关阅读:
    饿了么P7级前端工程师进入大厂的面试经验
    前端程序员面试的坑,简历写上这一条信息会被虐死!
    这次来分享前端的九条bug吧
    移动端开发必会出现的问题和解决方案
    创建一个dynamics 365 CRM online plugin (八)
    创建一个dynamics 365 CRM online plugin (七)
    创建一个dynamics 365 CRM online plugin (六)
    创建一个dynamics 365 CRM online plugin (五)
    使用User Primary Email作为GUID的问题
    怎样Debug Dynamics 365 CRM Plugin
  • 原文地址:https://www.cnblogs.com/new0801/p/6176973.html
Copyright © 2011-2022 走看看