互斥锁和条件变量~

互斥锁指代相互排斥,它是最基本的同步形式。互斥锁用于保护临界区,以保证任何时刻只有一个线程在执行其中的代码。
如下
lock_THE_MUtex(...)
临界区
unlock_the_mutex(...)
互斥锁的上锁和解锁一般通过下列三个函数
#include<pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mptr);
int pthread_mutex_trylock(pthread_mutex_t *mptr);
int pthread_mutex_unlock(pthread_mutex_t *mptr);
以上三个函数返回值均相同,成功返回0,出错返回错误值;
互斥锁的简单应用
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//互斥锁的声明

void* thread_fun1(void *arg)
{
    printf("This is thread fun 1.\n");
    pthread_mutex_lock(&mutex);    //线程1上锁
	printf("thread fun 1 lock.\n")
    sleep(3);
    printf("thread fun 1 unlock.\n");//线程1解锁
	pthread_mutex_unlock(&mutex);
    
}
void* thread_fun2(void *arg)
{
    printf("This is thread fun 2.\n");
    pthread_mutex_lock(&mutex);//线程2上锁
    printf("thread fun 2 lock.\n");
    pthread_mutex_unlock(&mutex);//线程2解锁
	printf("thread fun 2 unlock.\n");
}

int main()
{
    pthread_mutex_init(&mutex, NULL);
    pthread_t tid1, tid2;
    pthread_create(&tid1, NULL, thread_fun1, NULL);
    sleep(1);                                 //保证线程2能在线程1之后被创建
    pthread_create(&tid2, NULL, thread_fun2, NULL);

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    pthread_mutex_destroy(&mutex);
    return 0;
}

运行结果
可以看到创建线程1之后隔了一秒才进行创建线程2,所以先打印出线程1的信息

但由于线程1上锁后停留3秒,减去创建线程2停留的1秒,剩下两秒钟是足够让线程2运行一万次的,但是通过结果我们可以看到
线程2并没有继续运行,这是因为线程1此时已经上了锁,而线程2再次想要进行上锁是不可能了,这个时候就必须等线程1解锁之后才能够上锁。

比较官方的说法是:如果尝试给一个已由另外某个线程锁住的互斥锁上锁,那么pthread_mutex_lock将阻塞到该互斥锁解锁为止。而pthread_mutex_trylock是对应的非阻塞函数,如果该互斥锁已锁住,它就返回一个EBUSY错误。

即在线程1已经上锁的情况下线程2使用 pthread_mutex_trylock仍旧可以进行获取锁,以达到让线程继续执行的目的。pthread_mutex_trylock(pthread_mutex_t *nptr)的返回值上面已经说过就不再赘述。

条件变量是类型为pthread_cond_t的变量
与之相关的函数有
#include<pthread.h>
int pthread_cond_wait(pthread_cond_t *cptr,pthread_mutex_t *mptr);
int pthread_cond_signal(pthread_cond_t *cptr);
返回值类似互斥锁,成功返回0,出错返回正的错误值。

简单用法

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


pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;

void* thread_fun1(void *arg)
{
    int index = *(int*)arg;
    printf(" %d thread start\n",index);
    pthread_mutex_lock(&mutex);

    printf(" %d thread cond wait\n",index);
    pthread_cond_wait(&cond,&mutex);
    printf(" %d thread waked up\n",index);
    pthread_mutex_unlock(&mutex);
}

void* thread_fun2(void *arg)
{
    printf("this is thread 2\n");
    pthread_mutex_lock(&mutex);
    printf("cond signal thread\n");
    sleep(2);
    pthread_cond_broadcast(&cond);
    pthread_mutex_unlock(&mutex);
}

int main()
{
    pthread_t tid1[5],tid2;
    
    int i;
    for(i=0;i<5;++i)
    {
        pthread_create(&tid1[i],NULL,thread_fun1,&i);
        sleep(1);
    }

    sleep(2);
    pthread_create(&tid2,NULL,thread_fun2,NULL);

    for(i=0;i<5;++i)
    {
        pthread_join(tid1[i],NULL);
    }

    pthread_join(tid2,NULL);

    return 0;
}

 运行结果
例子很简单,循环创建5个线程并进行上锁解锁,在临界区用pthread_cond_wait函数使线程进入阻塞状态。

pthread_cond_signal为其唤醒函数,但一次只能唤醒一个线程,所以这里采用pthread_cond_broadcast函数将其全部唤醒,线程被唤醒后,在阻塞的地方继续运行。关于pthread_cond_broadcast函数的用法就不再赘述了,用法跟signal是一样的。这些函数其实用法都大同小异。还有pthread_cond_timewait等函数用法类似。

值得注意的是pthread_cond_timewait允许线程就阻塞时间设置一个限制值。而时间参数是一个timespec结构

struct timespec
{
    time_t tvsec; /* seconds */
    long tv_nsec; /* nanoseconds */
}


雨下整夜,我的爱溢出就像雨水   

嘻嘻嘻

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值