【C语言】【unix c】条件变量线程同步

    什么是条件变量?
        线程a等待某个条件成立,条件成立,线程a才继续向下执行。线程b的执行使条件成立,条件成立之后唤醒线程a,以继续执行。这个条件就是条件变量
        pthread_cond_t 就是条件变量类型

    对类型的封装如下:
        #include 

        pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //条件变量的静态初始化,定义变量可以用

        int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);
            功能:初始化一个条件变量
            参数:
                cond:指定要初始化的条件变量(指向结构pthread_cond_t的指针)
                cond_attr:NULL 默认的(用于设置条件变量是进程内还是进程间的)
            返回值:0 成功
                    非0 错误

       int pthread_cond_signal(pthread_cond_t *cond);
            功能:启动在等待条件变量变为真的一个线程,每次最多可以给一个线程发送
            参数:
                cond:指定条件变量
            返回值:0 成功
                 非0 错误

       int pthread_cond_broadcast(pthread_cond_t *cond);
            功能:启动所有的等待条件变量为真的线程
            参数:
                cond:指定条件变量
            返回值:0 成功
                    非0 错误

       int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);  //等待期间不会占用cpu,先解锁,然后进入睡眠状态,等待接受信号
            功能:等待条件变量为真(无条件等待)
            参数:
                cond:指定等待的条件变量
                mutex:等待之前需要解开的锁
            返回值:0 成功
                    非0 错误

       int   pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t *mutex, const struct timespec *abstime); //超时等待
            功能:超时等待,超时返回错误(计时等待)
            参数:
                cond:指定等待的条件变量
                mutex:等待之前需要解开的锁
                abstime:指定等待的时间
            返回值:0 成功
                    非0 错误

       int pthread_cond_destroy(pthread_cond_t *cond);
            功能:销毁一个条件变量
            参数:
                cound:指定要销毁的条件变量
            返回值:0 成功
                    非0 错误
    操作步骤:
        1、解开mutex锁
        2、让线程等待条件变量为真
        3、条件变量为真时加锁

    生产者和消费者(读者和写者)
    链表实现:生产者生产出来对象,放到链表头部,消费者从链表的头部取出消费

    第一个思考:两个线程如何同步访问链表的头部
    第二个思考:如果链表为空,消费者等待生产者生产对象
    第三个思考:生产者线程生产出对象需要通知消费者
        代码见 cond.c
        #include 
        #include 
        #include 
        #include 

        typedef struct node{
            int num;
            struct node  *next;
        }node_t;

        typedef node_t *list_t;
        list_t head=NULL;
        pthread_mutex_t mutex=\
                    PTHREAD_MUTEX_INITIALIZER;
        pthread_cond_t cond=\
                PTHREAD_COND_INITIALIZER;

        //消费者线程
        void *consume(void *arg){
            node_t *tmp;
            while(1){
                //加锁
                pthread_mutex_lock(&mutex);//对临界变量加锁
                if(head==NULL)//如果头部指向空,等待
                    pthread_cond_wait(&cond,&mutex);
                tmp=head;//将要删除的节点赋值给中间值,然后头指针指向下一个
                head=head->next;//
                //解锁
                pthread_mutex_unlock(&mutex);
                //消费tmp节点
                printf("consum:%d\n",tmp->num);
                free(tmp);
                tmp=NULL;
                sleep(rand()%5);
            }
        }

        //生产者线程
        void *product(void *arg){//函数的格式void *(*start_routine) (void *),返回值是指针,参数也是
            node_t *n;
            while(1){
                //生产一个新的节点
                n=(node_t *)malloc(sizeof(node_t));
                n->num=rand()%1000+1;
                printf("p:%d\n",n->num);
            //加锁
                pthread_mutex_lock(&mutex);
                //将新节点放入到链表的头部
                n->next=head;
                head=n;
            //解锁
                pthread_mutex_unlock(&mutex);
                //通知消费者
                pthread_cond_signal(&cond);
                sleep(rand()%5);
            }
        }
        int main(void){
            pthread_t pid,cid;
            //设置随机数的种子
            srand(time(NULL));
            //创建两个线程,用于生产者和消费者
            pthread_create(&pid,NULL,product,NULL);//创建线程后即执行该线程
            pthread_create(&cid,NULL,consume,NULL);//参数含义是(存放ID的缓存区,NULL缺省属性,线程的执行函数,函数的唯一参数)
            //等待线程的汇合
            pthread_join(pid,NULL);
            pthread_join(cid,NULL);
            //销毁mutex锁
            pthread_mutex_destroy(&mutex);
            pthread_cond_destroy(&cond);
            return 0;
        }

        tarena@ubuntu:~/day/day37$ gcc cond.c -lpthread
        tarena@ubuntu:~/day/day37$ a.out 
        p:637
        consum:637
        p:741
        consum:741
        p:243
        consum:243
        p:651
        consum:651
        p:252
        consum:252
        p:244
        p:612
        p:954
        p:627
        p:564
        consum:564
        p:941
        consum:941
        p:347
        consum:347
        p:28
        consum:28
        p:60
        p:174
        consum:174
        p:824
        p:359
        consum:359
        consum:824
        p:671
        p:8
        p:164
        ^C
    分析:链表会将之前没有出来的先压在下面,直到前面的输出完才会将他们输出来

你可能感兴趣的:(c语言,Linux,unix,c语言,线程)