Examples

注:摘自肖堃老师视频教程

任务同步- 任务间相互合作关系(直接相互制约关系)

两个或多个任务为了合作完成同一个工作,在执行速度或某个确定的时序点上必须相互协调,即一个任务的执行必须依赖另一个任务的执行情况。

程序设计中存在这样的情况 :多个线程都要访问临界资源,又要相互合作(线程间同时存在互斥关系和同步关系)

例如:线程A先执行某操作(例如对全局变量x的修改)后,线程B才能(根据变量X的值判断)执行另一个操作(可能是对变量x的修改),该如何实现?

linux提供了条件变量机制:条件变量与互斥量一起使用时,允许线程以互斥的方式阻塞等待特定条件的发生(同步)

步骤:

1)定义条件变量(pthread_cond_t类型),定义互斥量变量

2)初始化条件变量,初始化互斥量

3)触发条件线程x

  互斥量加锁 -> xx操作 -> 触发条件变量 -> 互斥量解锁

4)等待条件线程y

  互斥量加锁 -> 等待条件变量 -> xx操作 -> 互斥量解锁

5)销毁条件变量,销毁互斥量变量

1)条件变量定义和初始化

静态初始化:pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

动态初始化: 

    #include <pthread.h>

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

    参数和返回值:

       cond - 条件变量

       attr - 条件变量属性,若为NULL,则使用默认属性

       成功返回0,出错返回错误码

 2)条件变量销毁

  int pthread_cond_destroy( pthread_cond_t *cond )

    参数和返回值:

       cond  - 条件变量

       成功返回0,出错返回错误码

3)条件变量使用

pthread_cond_wait函数将使调用线程进入阻塞状态,直到条件被触发

int pthread_cond_wait( pthread_cond_t *cond, pthread_mutex_t *mutex)

参数和返回值:

  cond - 条件变量

  mutex - 互斥量

  成功返回0,失败返回错误码(可能传入的条件变量指针不正确,也可能传入的互斥量指针不正确)

为什么条件变量需要和互斥量配合使用

1> 条件变量的使用场景伴随共享资源的使用,例如全局变量

2> 在调用pthread_cond_wait前,需要使互斥量处于加锁状态,这样可以通过原子操作的方式,将调用线程放到该条件变量等待线程队列(临界资源)中

等待条件变量的操作:

1> 调用pthread_mutex_lock()

2> 调用pthread_cond_wait()

3> 调用pthread_mutex_unlock()

由于pthread_cond_wait()在被执行之前,需要先调用pthread_mutex_lock()进行互斥量加锁, 而pthread_cond_wait()可能导致调用该函数的线程被阻塞,

那么是否意味着被阻塞的线程保持了互斥量的加锁操作,从而导致系统的死锁呢?

其实,linux系统已经考虑到了这种情况,当调用pthread_cond_wait()后,内核会自动执行操作

  a. 在线程阻塞等待条件变量之前,调用pthread_mutex_unlock

  b. 若条件变量被其他线程触发,在该线程被唤醒后,调用pthread_mutex_lock,再次将该互斥量加锁

以上操作由内核自动完成,因此,调用pthread_cond_wait函数,无需考虑因为对互斥量加锁并阻塞,而导致可能出现的死锁的情况。

pthread_cond_signal和pthread_cond_broadcast可以触发条件变量并唤醒等待条件变量的线程

pthread_cond_signal唤醒该条件变量等待线程队列中的某一个线程

pthread_cond_broadcast唤醒该条件变量等待队列中的所有线程,这些线程会进行竞争

pthread_cond_signal( pthread_cond_t *cond )

pthread_cond_broadcast( pthread_cond_t *cond )

输入参数和返回值:

  cond - 条件变量

  成功返回0,失败返回错误码

#include <stdio.h>
#include <pthread.h>

pthread_mutex_t count_lock;
pthread_cond_t count_ready;

int count = 0;


void *decrement_count( void *arg )
{
    pthread_mutex_lock( &count_lock );
    printf( "decrement:waiting......
" );

    //进入阻塞状态,内核会先mutex_unlock,直到条件变量被唤醒,内核在执行mutex_lock
    pthread_cond_wait( &count_ready, &count_lock ); 

    //等待条件变量,期间互斥量仍然可用
    count = count - 1;
    printf( "decrement: count = %d
", count );
    pthread_mutex_unlock( &count_lock );
    printf( "decrement: quit
" );
    pthread_exit( NULL );
}

void *increment_count( void *arg )
{
    pthread_mutex_lock( &count_lock );
    printf( "increment:running
" );

    count += 1;
    pthread_cond_signal( &count_ready ); //触发条件变量

    printf( "increment: count = %d
", count );
    pthread_mutex_unlock( &count_lock );
    printf( "increment: quit
" );
    pthread_exit( NULL );
}





int main( )
{
    pthread_t tid1, tid2;
    count = 0;

    pthread_mutex_init( &count_lock, NULL );
    pthread_cond_init( &count_ready, NULL );

    pthread_create( &tid1, NULL, decrement_count, NULL );  //创建减法线程
    sleep(2);
    pthread_create( &tid2, NULL, increment_count, NULL );  //创建加法线程

    pthread_join( tid2, NULL );
    printf( "decrement quit
" );
    pthread_join( tid1, NULL );

    return 0;

}

编译并运行:

root@localhost:pthread# gcc -o thread_mutex_cond thread_mutex_cond.c -lpthread
root@localhost:pthread# ./thread_mutex_cond
decrement:waiting......
increment:running
increment: count = 1
increment: quit
decrement: count = 0
decrement: quit
decrement quit

原文地址:https://www.cnblogs.com/hjj801006/p/13042403.html