美文网首页
Mutex与semaphore与condition variab

Mutex与semaphore与condition variab

作者: 小幸运Q | 来源:发表于2020-04-02 11:13 被阅读0次

https://www.cnblogs.com/xudong-bupt/p/6707070.html


Mutex与semaphore:

Mutex上的锁只能自己上自己解锁,因为资源只有一个,可以认为是semaphore=1

信号量(Semaphore)是一个非负的整数计数器,相当于有多个资源共享。

打个比方:在早餐餐厅,大家要喝咖啡。如果用Mutex的方式,同时只有一个人可以使用咖啡机,他获得了咖啡机的使用权后,开始做咖啡,其他人只能在旁边等着,直到他做好咖啡后,另外一个人才能获得咖啡机的使用权。如果用Semaphore的模式,服务员会把咖啡做好放到柜台上,谁想喝咖啡就拿走一杯,服务员会不断做咖啡,如果咖啡杯被拿光了,想喝咖啡的人就排队等着。Mutex管理的是咖啡机的使用权,而Semaphore管理的是做好的咖啡数量。

mutex 是睡眠等待( sleep waiting )类型的锁,当线程抢互斥锁失败的时候,线程会陷入休眠。优点就是节省 CPU 资源,缺点就是休眠唤醒会消耗一点时间。另外自从 Linux 2.6版以后, mutex 完全用 futex 的 AP 实现了,内部系统调用的开销大大减小。

  • 阻塞型信号:pthread_mutex
pthread_mutex_t mutex;
pthread_mutex_init(&mutex,NULL);
pthread_mutex_lock(&mutex);
....
pthread_mutex_unlock(&mutex);
pthread_mutex_destory(&mutex);
# 调用pthread_mutex_destory之后,可以释放锁占用的资源,但这有一个前提上锁当前是没有被锁的状态。


condition variable

互斥锁有一个明显到缺点: 只有两种状态,锁定和非锁定。

而条件变量则通过允许线程阻塞并等待另一个线程发送唤醒信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用。

notify_one()和notify_all()

OS为每个条件变量维护一个等待队列称之为 waitingThreads。在 wait 时,线程会把自己放进去,signal 时,会从 waitingThreads 里取出一个线程,放入全局的 readyQueue 里,交由操作系统唤醒。


动手实践:

pthread_mutex_lock(&count_mutex);
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

#define NUM_THREADS 3 
#define TCOUNT      10 
#define COUNT_LIMIT 10 

int count = 0;
int thread_ids[3] = {0,1,2};
pthread_mutex_t count_mutex;
pthread_cond_t  count_threshold_cv;

void *inc_count(void *idp)
{
    int i = 0;
    int taskid = 0;
    int *my_id = (int*)idp;

    for (i=0; i<TCOUNT; i++) {
        pthread_mutex_lock(&count_mutex);
        taskid = count;
        count++;

        /*
          唤醒一个阻塞在该条件变量到线程
          如果没有线程被阻塞在条件变量上,那么调用pthread_cond_signal()将没有作用
        */
        pthread_cond_signal(&count_threshold_cv);

        printf("inc_count(): thread %d, count = %d, unlocking mutex\n", *my_id, count);
        pthread_mutex_unlock(&count_mutex);
        sleep(1);
    }
    printf("inc_count(): thread %d, Threshold reached.\n", *my_id);

    pthread_exit(NULL);
}

void *watch_count(void *idp)
{
    int *my_id = (int*)idp;
    printf("Starting watch_count(): thread %d\n", *my_id);

    pthread_mutex_lock(&count_mutex);
    while(count<COUNT_LIMIT) {
        sleep(3);
        /*
          函数将自动/原子到解锁mutex参数指向的互斥锁,并使当前线程阻塞在cv参数指向的条件变量上
          被阻塞的线程可以被pthread_cond_signal函数,pthread_cond_broadcast函数唤醒,也可能在被信号中断后被唤醒
          pthread_cond_wait函数的返回并不意味着条件的值一定发生了变化,必须重新检查条件的值. 
          本例子中使用类COUNT_LIMIT最为满足条件的值
          pthread_cond_wait函数返回时,相应的互斥锁将被当前线程锁定,即使是函数出错返回
        */
        pthread_cond_wait(&count_threshold_cv, &count_mutex);
        printf("watch_count(): thread %d Condition signal received.\n", *my_id);
    }

    count += 100;
    pthread_mutex_unlock(&count_mutex);
    pthread_exit(NULL);
}

int main (int argc, char *argv[])
{
    int i, rc;
    pthread_t threads[3];
    pthread_attr_t attr;

    /* Initialize mutex and condition variable objects */
    pthread_mutex_init(&count_mutex, NULL);
    pthread_cond_init (&count_threshold_cv, NULL);

    /* For portability, explicitly create threads in a joinable state */
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    pthread_create(&threads[0], &attr, inc_count,   (void *)&thread_ids[0]);
    pthread_create(&threads[1], &attr, inc_count,   (void *)&thread_ids[1]);
    pthread_create(&threads[2], &attr, watch_count, (void *)&thread_ids[2]);

    /* Wait for all threads to complete */
    for (i=0; i<NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }
    printf ("Main(): Waited on %d  threads. Done.\n", NUM_THREADS);

    /* Clean up and exit */
    pthread_attr_destroy(&attr);
    pthread_mutex_destroy(&count_mutex);
    pthread_cond_destroy(&count_threshold_cv);
    pthread_exit(NULL);

    return 0;
}
g++ condv.cpp -lpthread -o condv && ./condv

相关文章

网友评论

      本文标题:Mutex与semaphore与condition variab

      本文链接:https://www.haomeiwen.com/subject/noqqyhtx.html