Linux ·

Linux C 条件变量cond的使用记录

条件变量是实现线程间同步的一种方法,条件变量用来自动阻塞一个线程,直到收到收到一个cond信号或其它特殊情况发送,条件变量使用的时候必须与互斥量同时使用,这是为了保证条件量在线程间操作的“原子性”。

1、创建一个条件变量cond:

int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr);

在初始化一个条件变量时如果attr为 NULL,测使用默认值初始化一个条件变量cond,相当于下面的方式定义一个条件变量cond;

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

2、销毁一个条件变量cond:

int pthread_cond_destroy(pthread_cond_t *cond);

可以销毁一个条件变量cond,使其未初始化。一个被引用的条件变量是不可被销毁的,使用一个被销毁的条件变量将造成为止的后果,在默认条件下测试,将导致线程将直处于阻塞状态。

3、等待一个条件变量:

  int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t *mutex, const struct timespec *restrict abstime);
  int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

将导致线程阻塞在条件变量cond,应用程序应确保被mutex锁定的线程调用这些函数,否则可能导致未知错误。

这两个函数在执行开始将自动释放mutex,等待条件变量之后将自动锁定mutex,如果有其它线程正在调用mutex将导致线程阻塞。具体执行过程如下所示:

pthread_mutex_cond_unlock(mutex);

pthread_cond_wait(cond);

pthread_mutex_cond_lock(mutex);

在包含pthread_cond_wait函数的线程结束前一定要释放mutex,否则可能会造成其它等待cond的线程一直阻塞。如果有其它线程获得了互斥锁mutex,也将导致cond的线程阻塞。

4、唤醒一个被cond阻塞的线程:

  int pthread_cond_broadcast(pthread_cond_t *cond);
  int pthread_cond_signal(pthread_cond_t *cond);

pthread_cond_signal将唤醒一个被阻塞的线程,pthread_cond_broadcast是唤醒所有被阻塞的线程,如果没有被阻塞的线程pthread_cond_signal与pthread_cond_broadcast也将正确返回,但是其产生的信号将不起任何作用。

5、使用pthread_cond_timedwait实现精确延时,在单个线程中的cond与mutex可以直接用下面方式实现精确延时:

 

 

void set_abswaittime(struct timespec*outtime, int ms)
{

  long sec ;
  long usec ;
  struct timeval tnow;
  gettimeofday(&tnow, NULL);
  usec = tnow.tv_usec + ms*1000;
  sec = tnow.tv_sec+usec/1000000;
  outtime->tv_nsec=(usec%1000000)*1000;
  outtime->tv_sec=sec;
}

pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
struct timespec abstime;
set_abswaittime(&abstime,1000);
pthread_cond_wait(&tcond, &tmutex, &abstime);   

 

 

6、条件变量使用测试,测试代码如下:

 

 

//
// 创建人: levy
// 创建时间:May 25, 2017
// 功能:main.c
// Copyright (c) 2016 levy. All Rights Reserved.
// Ver          变更日期        负责人                          变更内容
// ──────────────────────────────────────────────────────────────────────────
// V0.01        May 25, 2017                  levy          初版
//

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>

pthread_mutex_t test_mutex=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t test_cond=PTHREAD_COND_INITIALIZER;

int test_count;

void * test_thread1(void *arp)
{
    int s=(int)arp;
    printf("I am thread %ld ,I will sleep %d s .\n",pthread_self(),s);
   sleep(s);
    pthread_mutex_lock(&test_mutex);

    pthread_cond_wait(&test_cond,&test_mutex);
    test_count++;
    printf("my thread id is %ld ,testcount=%d \n",pthread_self(),test_count);
    pthread_mutex_unlock(&test_mutex);
    pthread_exit(NULL);
}

 

int  main(void )
{
    pthread_t th[3];
    test_count=0;
    for(int i=0;i<3;i++)
    {
        pthread_create(&th[i],NULL,test_thread1,i);
    }

    for(int i=0;i<3;i++)
    {
     sleep(3);
        pthread_cond_signal(&test_cond);
    }
    for(int i=0;i<3;i++)
    {
        pthread_join(th[i],NULL);
    }

    pthread_exit(NULL);
}

 

输出结果:

I am thread 140391800571648 ,I will sleep 1 s .
I am thread 140391808964352 ,I will sleep 1 s .
I am thread 140391792178944 ,I will sleep 1 s .
my thread id is 140391808964352 ,testcount=1
my thread id is 140391800571648 ,testcount=2
my thread id is 140391792178944 ,testcount=3

参与评论