zoukankan      html  css  js  c++  java
  • 多线程的三种同步机制

    1,互斥锁;

      这个感觉只是保护了资源不会被同时使用,至于同步???还没怎么理解。

      基本函数:  

      通过锁机制实现线程间的同步。同一时刻只允许一个线程执行一个关键部分的代码。

      int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutex_attr_t *mutexattr); 或pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIER。前者是动态初始化,后者是静态。

      int pthread_mutex_lock(pthread_mutex *mutex);

      int pthread_mutex_destroy(pthread_mutex *mutex);

      int pthread_mutex_unlock(pthread_mutex *

      这个用得比较多,不做详细说明。

    2,条件变量

       条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。

      基本函数:

      初始化:同互斥锁一样也是两种方式 pthread_cond_t cond=PTHREAD_COND_INITIALIER和int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);  

      int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex); //等待条件变量

      int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime); //延时等待条件变量

      int pthread_cond_destroy(pthread_cond_t *cond); //删除条件变量

      int pthread_cond_signal(pthread_cond_t *cond); //解除在一个等待的线程阻塞

      int pthread_cond_broadcast(pthread_cond_t *cond);  //解除所有线程的阻塞

      看个例子:(此例子着重说明pthre_cond_signal/broadcast,如果没有wait,依旧正常返回,并且不会保留到下次wait,通俗点:我解除阻塞的时候,你没有阻塞,那哥们我先走了,下次你阻塞,得等到我下次来解除,过时不候~~)

    #include <pthread.h>
    #include <stdio.h>
    #include <sys/signal.h>
    #include <semaphore.h>  
    
    
    static pthread_mutex_t vpu_mutex1 = PTHREAD_MUTEX_INITIALIZER;
    static pthread_mutex_t vpu_mutex2 = PTHREAD_MUTEX_INITIALIZER;
    static pthread_cond_t vpu_cond1 = PTHREAD_COND_INITIALIZER;
    static pthread_cond_t vpu_cond2 = PTHREAD_COND_INITIALIZER;
    
    void* test_thread1(void *arg)
    {
        sleep(2);
        pthread_mutex_lock(&vpu_mutex1);
        pthread_cond_signal(&vpu_cond1);
        pthread_mutex_unlock(&vpu_mutex1);
    
    sleep(5);
        
    }
    
    void* test_thread2(void *arg)
    {
        sleep(1);
        pthread_mutex_lock(&vpu_mutex2);
        pthread_cond_signal(&vpu_cond2);
        pthread_mutex_unlock(&vpu_mutex2);
        sleep(5);
    }
    
    int main()
    {
        int i, j, ret;
            
        pthread_t test_id1;
        pthread_t test_id2;
    
        ret = pthread_create(&test_id1, NULL, test_thread1, NULL);
        if (ret != 0)
        {
            printf("Create pthread error!
    ");
            return -1;//exit(1);
        }
    
        ret = pthread_create(&test_id2, NULL, test_thread2, NULL);
        if (ret != 0)
        {
            printf("Create pthread error!
    ");
            return -1;
            //exit(1);
        }
        pthread_mutex_lock(&vpu_mutex1);
        pthread_cond_wait(&vpu_cond1, &vpu_mutex1);
        pthread_mutex_unlock(&vpu_mutex1);
    
        pthread_mutex_lock(&vpu_mutex2);
        pthread_cond_wait(&vpu_cond2, &vpu_mutex2);
        pthread_mutex_unlock(&vpu_mutex2);
        
        printf("hello world
    ");
        pthread_join(test_id1, NULL);
    
        return 0;
    }

    上面的例子是不会打印出hello world的。因为等不到vpu_cond2的接触。如果将test_thread1和test_thread2中的sleep对调,就可以了。 这个简单,将多了就啰嗦了。

    说明:

       (1)pthread_cond_wait 自动解锁互斥量(如同执行了pthread_unlock_mutex),并等待条件变量触发。这时线程挂起,不占用CPU时间,直到条件变量被触发(变量为ture)。在调用pthread_cond_wait之前,应用程序必须加锁互斥量。pthread_cond_wait函数返回前,自动重新对互斥量加锁(如同执行了pthread_lock_mutex)。

        (2)互斥量的解锁和在条件变量上挂起都是自动进行的。因此,在条件变量被触发前,如果所有的线程都要对互斥量加锁,这种机制可保证在线程加锁互斥量和进入等待条件变量期间,条件变量不被触发。条件变量要和互斥量相联结,以避免出现条件竞争——个线程预备等待一个条件变量,当它在真正进入等待之前,另一个线程恰好触发了该条件(条件满足信号有可能在测试条件和调用pthread_cond_wait函数(block)之间被发出,从而造成无限制的等待)。

    3,信号量

      #include <semaphore.h>

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

          这是对由sem指定的信号量进行初始化,设置好它的共享选项(linux 只支持为0,即表示它是当前进程的局部信号量),然后给它一个初始值VALUE

      两个原子操作函数:

      int sem_wait(sem_t *sem);

      int sem_post(sem_t *sem);

      这两个函数都要用一个由sem_init调用初始化的信号量对象的指针做参数。

      sem_post:给信号量的值加1

      sem_wait:给信号量减1;对一个值为0的信号量调用sem_wait,这个函数将会等待直到有其它线程使它不再是0为止。

      int sem_getvalue(sem_t *sem, int *sval);

      获取信号的值,存入sval中。

      int sem_destroy(sem_t *sem);

      这个函数的作用是再我们用完信号量后都它进行清理。归还自己占有的一切资源。

      

      看个例子:跟上面那个一样,但是信号是可以保留的,因为sem_post后,信号量+1,sem_wait信号量-1,即只要sem不为0,一遇wait就向下执行。

      

    #include <pthread.h>
    #include <stdio.h>
    #include <sys/signal.h>
    #include <semaphore.h> 
    
    sem_t sem_1;
    sem_t sem_2;
    
    void* test_thread1(void *arg)
    {
        sleep(3);
    sem_post(&sem_1);
    
    sleep(5);
        
    }
    
    void* test_thread2(void *arg)
    {
        sleep(1);
        sem_post(&sem_2);
        sleep(5);
    }
    
    int main(int argc, char **argv)
    {
        int i, j, ret;
        
        sem_init(&sem_1, 0, 0);
        sem_init(&sem_2, 0, 0);
    
        pthread_t test_id1;
        pthread_t test_id2;
    
        ret = pthread_create(&test_id1, NULL, test_thread1, NULL);
        if (ret != 0)
        {
            printf("Create pthread error!
    ");
            return -1;//exit(1);
        }
    
        ret = pthread_create(&test_id2, NULL, test_thread2, NULL);
        if (ret != 0)
        {
            printf("Create pthread error!
    ");
            return -1;
            //exit(1);
        }
    
        
    
        sem_wait(&sem_1);
        sem_wait(&sem_2);
    //    sem_getvalue(&single_seq, &sem_value);
        
        printf("hello world
    ");
        pthread_join(test_id1, NULL);
    
    
    }

    通过上面两个例子对比,可得条件变量和信号量的区别。当然如果要使得条件变量,具有信号量的功能。可以这么做:

    再定义一个全局变量flag,判断flag的值,比如 在发送端,先flag++,在pthread_cond_signal; 在接收端while(flag<2)pthread_cond_wait();

    这样就ok了。为什么不使用一个全局变量while(flag<2);呢?因为这样很占用CPU,为什么不while(flag<2)usleep(timecnt);呢?

    在线程里面sleep函数是不安全的!下篇接受,并解决线程延时问题。

  • 相关阅读:
    C# 将数据导出到Excel汇总
    jquery 常用技巧
    JavaScript:世界上误解最深的语言
    对于jQuery中$.ajax方法的新认识
    JQuery上传插件Uploadify使用详解
    HTTP中Get与Post的区别
    Javascript中最常用的55个经典技巧
    C# params参数的应用
    10种JavaScript特效实例让你的网站更吸引人
    jQuery设计思想
  • 原文地址:https://www.cnblogs.com/cyc2009/p/3974348.html
Copyright © 2011-2022 走看看