[操作系统] 同步与互斥锁问题

本文介绍了并发进程的概念,讨论了并发进程中竞争与协作的关系,重点讲解了临界区、互斥锁以及如何使用互斥锁解决如订票问题中的数据一致性问题。通过C语言示例展示了如何使用互斥锁来管理和保护临界区。
摘要由CSDN通过智能技术生成

并发

首先来了解一下,什么是并发进程/线程

在内存中同时存在的若干个进程/线程,由操作系统的调度程序采用适当的策略将他们调度到CPU上运行,同时维护队列

  • 宏观上,多个并发的进程/线程看起来是同时运行
  • 微观上,它们是交替运行(Interleaving)

由于进程/线程切换速度很快,看起来好像是"同时"运行。

并发进程之间的关系

并发进程之间有独立关系和交互关系

如果是交互关系,则又可分为竞争(Race)和协作关系(Cooperation)

竞争

竞争关系就好比两条分路的车(线程)争夺同一个匝道(资源),道路上只能有一辆车运行,另外一辆车需要等待(waiting).
race

协作

协作关系可以理解为,匝道上每过两辆车,此时才允许分路上的一辆车进入匝道,在此期间分路上的车需要等待(waiting).
coopetation

产生的一些问题

竞争关系为例,如果两辆车同时进入了匝道,相当于多个线程并发操作了同一个资源
给出一个经典的订票问题

T = x;  // x表示剩余票数
if(T >= 1) {
	x = T - 1;  
}

假设剩余两张票(x=2),如果两个线程(T1, T2)同时进入了订票系统,并且它们交替执行

  1. T1线程执行 T = x,此时T = 2
  2. 进程切换, T2线程执行T = x,此时T = 2
  3. T2线程进行if语句判断,x被赋值为1
  4. 进程切换,T1线程进行if语句判断,x被赋值为1

对于现实生活,两个人同时在买票平台上购买了一张票。可是最后平台的余票只减少了一张!这显然不合理。
所以我们需要一种机制,来解决这种情况。

同步

首先来看一段定义

Process Synchronization means a mechanism to maintain the consistency of data shared in cooperative processes.

意思是,同步机制指维护协作的进程之间的共享数据一致性
常用的两种同步工具有互斥锁和信号量, 本文暂且介绍互斥锁

互斥锁

Mutex Locks: Operating-System designers build software tools to solve the critical-section problem. The simplest of these tools is the mutex lock.

意味着,互斥锁是解决临界区问题的工具,同时它的使用也较为简单

那么,什么是临界区呢?

临界区

每个并发进程可能都有一段代码块,这段代码块中,进程可能会改变一些共有的变量。这段代码块被称之为临界区(Critical-Section)。
该系统的重要特点是,当一个进程在临界区执行时,其它进程不能执行。
对于临界区问题,我们需要设计一种使得各进程之间可以协作的协议(protocol)

进程进出临界区协议 critical-section protocol

对于临界区的管理,我们有三个准则

  • Mutual exclusion(Mutex): 互斥,当一个进程在临界区执行时,其它进程不能执行。
  • Progress: 当一个线程运行完毕(使用完资源)后,必须开放这块资源的使用权。让别的线程可以使用资源
  • Bounded waiting: 不能让正在等待的线程等待太久

互斥锁解决订票问题

基本思路是,我们需要在使用临界区前,对这块区域上锁(Lock)
使用完临界区后,对这块区域解锁(Unlock)
这也就意味着,当一个线程在买票时,另一个线程不能干预。

实现代码(C):

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

#define THREAD_NUM 2
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; // 定义一把锁
int ticketAmount = 2; // 余票

void *ticketAgent(void *arg)
{
    pthread_mutex_lock(&lock); // acquire lock
    // -----临界区-----
    int t = ticketAmount;
    if (t > 0)
    {
        printf("One ticket sold!\n");
        t--;
    }
    else
    {
        printf("Ticket sold out!!\n");
    }
    ticketAmount = t;
	// -----临界区-----
    pthread_mutex_unlock(&lock);  // release lock
    pthread_exit(0); // 线程结束
}

int main(int argc, char const *argv[])
{
    pthread_t ticketAgent_tid[THREAD_NUM];
    for (int i = 0; i < THREAD_NUM; i++)
    {
        pthread_create(ticketAgent_tid + i, NULL, ticketAgent, NULL); // 线程创建函数
    }
    for (int i = 0; i < THREAD_NUM; i++)
    {
        pthread_join(ticketAgent_tid[i], NULL);
    }

    printf("The left ticket is %d\n", ticketAmount);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值