Linux——线程 三 (互斥量)

我们都知道每个线程都有自己独立的栈空间,自己使用的变量地址也在栈空间内。但是有时候,线程访问的变量都需要线程共享,这些变量称为共享变量,通过数据共享完成线程之间的交互。
我们在进程中了解到,多个进程同时访问一个共享变量的时候,会引发很多问题。所以进程之间需要访问共享变量的时候,需要互斥。

而对应的,我们线程访问共享变量,也需要这样的互斥操作。

我们从一个卖票系统看看,如果没有使用互斥相关操作,看看会出现什么样的结果。

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

int ticket = 4;        //票的总数

void *rout(void *arg)
{
    char *id = (char *)arg;
    while(1)
    {
        if(ticket > 0)
        {
            usleep(1000);
            printf("%s sell ticket:%d \n",id,ticket);
            ticket--;

        }
        else
        {
            break;
        }
    }
}

int main()
{
    pthread_t tid1,tid2,tid3;

    pthread_create(&tid1,NULL,rout,"thread1");
    pthread_create(&tid2,NULL,rout,"thread2");
    pthread_create(&tid3,NULL,rout,"thread3");

    pthread_join(tid1,NULL);
    pthread_join(tid1,NULL);
    pthread_join(tid1,NULL);

    return 0;
}

看一下运行结果:
这里写图片描述

很明显,运行的结果显示,不符合我们预期的效果。

我们的票数为4张,但是可以看到最后thread2 都卖到了 -1 张票了,这是不符合实际的问题的结果。

由于ticket 是全局变量,每个线程都可以访问到它,每个线程都在可能切换到运行状态,在线程函数里,出现了usleep() 等待,这时候系统可能切换到另一个进程中,又卖出了一张票,等该线程的运行时间到了后,再返回原来线程的时候,还继续对票数减一了。这就导致了程序的不符合实际性。

我们应该怎么解决这个问题呢?
1.代码必须要有互斥行为,当代码进入临界区执行时,不允许其他线程进入该临界区。
2.如果多个线程同时要求执行临界区的代码,并且临界区没有线程在执行时,那么只允许一个线程进入该临界区。
3.如果线程不在临界区中执行,那么该线程不能阻止其他线程进入到临界区。

这就是给临界区上了一把锁。 Linux上提供的这边锁叫做互斥量。

我们还可以这样定义互斥量:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER ;

这样定义的互斥量不需要进行初始化和删除,系统会自动的初始化和删除。

互斥量:
1.定义一个互斥量  pthread_mutex_t mutex

2.初始化信号量 pthread_mutex_init(&mutex,NULL);  //初始化成1

3.上锁 pthread_mutex_lock(&mutex);
        1->0,返回
        0   ,等待


4.销毁 pthread_mutex_destroy(&mutex); 

这样我们改进一下我们的买票系统:

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

int ticket = 4;

//pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_t mutex;     //定义互斥量

void *rout(void *arg)
{
    char *id = (char *)arg;
    while(1)
    {
        pthread_mutex_lock(&mutex);                     //上锁
        if(ticket > 0)
        {
            usleep(1000);
            printf("%s sell ticket:%d \n",id,ticket);
            ticket--;
            pthread_mutex_unlock(&mutex);            //解锁
        }
        else
        {
            pthread_mutex_unlock(&mutex);            //解锁
            break;
        }
    }
}

int main()
{
    pthread_t tid1,tid2,tid3;
    pthread_mutex_init(&mutex,NULL);            //初始化互斥量

    pthread_create(&tid1,NULL,rout,"thread1");
    pthread_create(&tid2,NULL,rout,"thread2");
    pthread_create(&tid3,NULL,rout,"thread3");

    pthread_join(tid1,NULL);
    pthread_join(tid1,NULL);
    pthread_join(tid1,NULL);

    pthread_mutex_destroy(&mutex);                //销毁互斥量

    return 0;
}

运行结果图:
这里写图片描述

添加了互斥量过后,该系统的买票结果与我们的预想效果一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值