Linux——线程互斥与同步

一、线程互斥

1.1 线程间互斥的概念

在学习管道的时候,管道是自带同步与互斥的。而在线程中,当多个线程没有加锁的情况下同时访问临界资源时会发生混乱。在举例之前,先了解几个概念。

  • 临界资源:多个线程执行流共享的资源叫做临界资源
  • 临界区:每个线程内部访问临界资源的代码叫做临界区
  • 互斥:任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用
  • 原子性:不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么未完

1.2 互斥量

大部分情况,线程使用的数据都是局部变量,变量的地址空间在线程栈空间内,这种情况,变量归属单个线程,其他线程无法获得这种变量。但有时候,很多变量都需要在线程间共享,这样的变量称为共享变量,可以通过数据的共享,完成线程之间的交互。多个线程并发的操作共享变量,会带来一些问题。

我们可以通过一个买票的例子,来看这块问题。

int ticket = 2000;
void *STicket(void *asg)
{
    while (1)
    {
        if (ticket > 0)
        {
            usleep(100);
            printf("%s sang ticket:%d \n", (char *)asg, ticket--);
        }
        else
        {
            break;
        }
    }
    return NULL;
}

int main()
{
    pthread_t t[4];
    int i;
    for (i = 0; i < 4; i++)
    {
        char *p = (char *)malloc(sizeof(char) * 64);
        sprintf(p, "pthread t%d", i);
        pthread_create(&t[i], NULL, STicket, (void *)p);
    }
    pthread_join(t[0], NULL);
    pthread_join(t[1], NULL);
    pthread_join(t[2], NULL);
    pthread_join(t[3], NULL);

    return 0;
}

我们在运行结果中可以看到,票的数量本不可能出现负数的,但是在结果中出现了,那么这就是一个问题。
多个线程并发的访问同一块临界资源,我们用t1,t2,t3,t4,来表示四个线程。一开始票的数量有1000张。

《出现问题1》当t1首先访问到票时,判断票还有剩余,于是拿走一张票,票还剩999张。但是这些线程是并发执行的,有可能多个线程同时拿到票,且通过对票进行减减操作,那么这个票是重复了。

《出现问题2》当t3拿到票的时候,刚准备对票进行减减,时间片就到了,线程退出,那么在t3这个线程内把读取到的票的数量保存起来,当t3这个线程有运行时,先恢复上下文数据,然后对山下文数据中保存票的数量进行减减,当t3这个线程完成了操作后,把剩余票的数量进行更新,那么在t3没有运行前,票已经抢完了,但是t3它不知道,然后又把票的数量进行更新了,票又回来了,这个时候又出错了。出现负数的情况就是这样。

在我们判断票是否有剩余的时候,和对票减减的时候,并不是具有原子性的,因为这个时候,其他线程也在进行抢票,可能拿到重复的票。我们可以通过汇编来验证是否具有原子性。

int main()
{
    int a = 5;
    a--;
    return 0;
}

--操作并不是原子性,而是对应了三条汇编:

  • load :将共享变量ticket从内存加载到寄存器中
  • update : 更新寄存器里面的值,执行-1操作
  • store :将新值,从寄存器写回共享变量ticket的内存地址

想要解决上面的问题,需要做到三点:

  • 代码必须要有互斥行为:当一个线程的代码进入临界区执行时,不允许其他线程进入该临界区。
  • 如果多个线程同时要求执行临界区的代码,并且临界区没有线程在执行,那么只能允许一个线程进入该临界区
  • 果线程不在临界区中执行,那么该线程不能阻止其他线程进入临界区。

而以上的三点本质就是加一把锁,在Linux上提供的这把锁叫做互斥量

先要理解这个锁。当多个线程同时要执行临界区的代码,那么谁先申请到这把锁,谁就执行,其他的线程就开始进行等待,等待这把锁被释放,然后申请这把锁。

1.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值