• 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

  • 相关阅读:
    Session_End引发的性能问题!
    可能引发性能问题的几个写法,看看你占哪一个.
    优化你的DiscuzNT3.0,让它跑起来(2)发帖回帖篇
    什么是经济学
    生产可能性边界和机会成本
    九宫格的实现(转)
    LAMP的安装和配置
    iPhone 开发过程中的一些小技术的总结(转)
    有效的利用资源边际成本与边际利益
    Dijkstra算法(注:单源最短路径的贪心算法)和数学归纳法<转>
  • 原文地址:https://www.cnblogs.com/hjj801006/p/13042403.html
Copyright © 2020-2023  润新知