Linux线程间同步机制_条件变量

来源:互联网 发布:六级阅读怎么提高知乎 编辑:程序博客网 时间:2024/04/29 22:51

    有时看网上的博客自己会纳闷,进程间的同步机制和线程间的同步机制分别是什么?

    其实进程之间是不用同步机制的,因为进程之间资源不共享,不需要同步机制来对所谓的临界资源进行保护,所以通常我们只讨论进程间的通信机制,有时候进程间的通信也称为进程间的同步,有管道,有名管道,信号量,消息队列,共享内存,socket, poll, epoll等,其实还有文件I/O,只是效率太慢不被采用,但是也能够实现进程之间的通信。

    由于一个进程内的所有的线程之间资源共享,所以多个线程可以同时对某个数据资源进行操作。所以为了保护临界资源只能被一个线程使用,因此采用线程间的同步机制。有:互斥量,条件变量,信号量,读写锁,自旋锁,屏障等机制。

    下面是自己对条件变量的一点总结

     利用信号量对临界资源进行加锁,解锁保护,可以保证某一时刻只有一个线程拿到锁对临界区进行操作,但是通常情况下会将互斥量和条件变量结合使用,这样可以解决一些不必要的麻烦。例如:

    (1)由于线程之间是异步进行的,所以每个线程得到锁的概率依线程的优先级而决定。所以说哪个线程下次能得到锁是不一定的,那么如果想让特定的线程去对资源进行操作可以利用条件变量,让系统立即调度拥有特定条件变量的线程,从而避免了多线程竞争。

    (2)如果一个线程得到锁,那么其他的线程得不到锁而处于忙等状态,等到这个线程释放锁,但是这个线程又再次得到锁,释放锁,就这样不停的加锁,解锁,从而形成死锁。但是条件变量可以有效的避免这种死锁的情况。

    (3)由于一个线程得到锁,其他的线程则处于忙等状态,不停的去查询锁有没有被释放,这样浪费ie大量的cpu资源,利用条件变量则使得不到锁的线程处于阻塞状态,等到有锁的时候去通知线程,这样效率高。

    条件变量最重要的一个函数的解析:

    pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex)

这个函数会先阻塞自身线程,然后解锁,直到别的线程拿到锁对临界资源进行操作,等到某一条件用pthread_cond_signal()唤醒对应的条件变量。则被阻塞的线程继续从阻塞的那块进行加锁,并且完成后面的代码。

例子:

    线程一负责打印奇数,线程二负责打印偶数,数值value是临界资源,只能允许某个时刻只能有一个线程对其进行操作。


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

using namespace std;
#define MAXNUM (10)

pthread_t tid[2];
pthread_mutex_t mutex;
pthread_cond_t ji, ou;
int value = 1;

void *pthread_ji(void *arg)
{
    
    int result;
    result = pthread_mutex_lock(&mutex);
    if(result != 0){
        return (void *)result;
    }
    while(value < MAXNUM){
        if(value % 2 == 1){
            printf("argc[%d]:%d\n", value, value);
            sleep(1);
            value++;
            pthread_cond_signal(&ou);
        }else{
            pthread_cond_wait(&ji, &mutex);     //当value值不为奇数时,走到这个分支,线程一阻塞,并且释放锁,直到
        }                                                           //第二个线程拿到锁并且对value进行操作,value符和条件为奇数时,此时
    }                                                               //用pthread_cond_signal(&ji)通知线程一,线程一再次拿到锁继续从阻塞的

                                                                    //的代码执行。

   pthread_mutex_unlock(&mutex);
}

void *pthread_ou(void *arg)
{
    int result;
    result = pthread_mutex_lock(&mutex);
    if(result != 0){
       return (void *)result;
    }
    while(value < MAXNUM){
        if(value % 2 == 0){
            printf("argc[%d]:%d\n", value, value);
            sleep(1);
            value++;
            pthread_cond_signal(&ji);
        }else{
            pthread_cond_wait(&ou, &mutex);
        }
    }
    pthread_mutex_unlock(&mutex);
}

int main(int argc, char *argv[])
{
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&ji, NULL);
    pthread_cond_init(&ou, NULL);
    pthread_create(&tid[0], NULL, pthread_ji, NULL);
    sleep(1);
    pthread_create(&tid[1], NULL, pthread_ou, NULL);

    pthread_join(tid[0], NULL);
    pthread_join(tid[1], NULL);
    pthread_mutex_destroy(&mutex);

}

    注意这里有个问题,线程可能在阻塞于pthread_cond_wait调用期间被取消,则由于没有解锁而造成死锁的情况,为了解决这个问题我们可以利用线程取消处理机制。

      int pthread_cancel(pthread_t tid)

比如,多个线程同时完成一个任务,但是有个线程最早完成,则最早完成的这个线程可以用线程取消函数。

这个函数只有在两种情况下被调用,其他情况是不会被调用的:

    (1)线程被别的线程取消。

    (2)线程自己终止调用pthread_exit()。

   


 

0 0
原创粉丝点击