1 临界区问题
临界区问题
- 每个并发进程都有一段被称作临界区的代码,该过程可能正在更改公共变量、更新表、写入文件等。
- 该系统的重要特征是,当一个进程正在其关键部分执行,没有其他进程是被允许在其关键部分中执行。也就是说,没有两个进程同时在其关键部分中执行。
- 临界区问题就是去设计一个协议可以使得线程之间协作。
**进程进出临界区协议 **
- 进入临界区前在entry section要请求许可;
- 离开临界区后在exit section 要归还许可。
** 临界区管理准则 **
- Mutual exclusion (Mutex):互斥
- Progress:前进
- Bounded waiting:有限等待
有空让进,则一而入,无空等待,有限等待,让权等待。
2 互斥锁
MUTEX LOCKS
- Operating-systems designers build software tools to solve the critical-section problem. The simplest of these tools is the mutex lock.
- A process must acquire the lock before entering a critical section;
- It must release the lock when it exits the critical section.
** 锁的基本操作 **
原子操作
- Atomic operations mean the operation can NOT be interrupted while it’s running.
- 原子操作(原语)是操作系统重要的组成部分,下面2条硬件指令都是原子操作,它们可以被用来实现
对临界区的管理(也就是“锁”)。
- test_and_set()
- compare_and_swap()
** 锁的实现 **
** 忙式等待(BUSY WAITING) **
- 忙式等待是指占用CPU执行空循环实现等待
- 这种类型的互斥锁也被称为“自旋锁”(spin lock)
- 缺点:浪费CPU周期,可以将进程插入等待队列以让出CPU的使用权;
- 优点:进程在等待时没有上下文切换,对于使用锁时间不长的进程,自旋锁还是可以接受的;在多处理器系统中,自旋锁的优势更加明显。
3 互斥锁实验
- 订票系统(临界区的管理)
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int ticketAmount = 2; //Global Variable
void* ticketAgent(void* arg){
int t = ticketAmount;
//sleep(1);
if (t > 0)
{
printf("One ticket sold!\n");
t--;
}else{
printf("Ticket sold out!!\n");
}
ticketAmount = t;
pthread_exit(0);
}
int main(int argc, char const *argv[])
{
pthread_t ticketAgent_tid[2];
for (int i = 0; i < 2; ++i)
{
pthread_create(ticketAgent_tid+i, NULL, ticketAgent,NULL);
}
for (int i = 0; i < 2; ++i)
{
pthread_join(ticketAgent_tid[i],NULL);
}
printf("The left ticket is %d\n", ticketAmount);
return 0;
}
该份代码用一个线程函数创建了两个线程,这种创建方法可以使用循环来减少代码的书写量(23行至28行),30行至33行学习如何用循环来等待所有线程结束。两个线程作为售票终端共享一个全局变量ticketAmount,两个线程运行结束后在主线程中打印余票量,编译运行这份代码,观察结果。
然后找出临界区,用互斥锁对临界区进行管理,阅读并运行下面的代码。
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int ticketAmount = 2; //Global Variable
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; //Global lock
void* ticketAgent(void* arg){
pthread_mutex_lock(&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);
pthread_exit(0);
}
int main(int argc, char const *argv[])
{
pthread_t ticketAgent_tid[2];
for (int i = 0; i < 2; ++i)
{
pthread_create(ticketAgent_tid+i, NULL, ticketAgent,NULL);
}
for (int i = 0; i < 2; ++i)
{
pthread_join(ticketAgent_tid[i],NULL);
}
printf("The left ticket is %d\n", ticketAmount);
return 0;
}
代码说明:
a. pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; //创建一个互斥锁
b. pthread_mutex_lock(&lock); //上锁
c. pthread_mutex_unlock(&lock); //开锁