avatar

【操作系统】操作系统基础篇二

进程管理之进程同步

进程间的同步

为什么需要进程间同步

生产者-消费者问题

有一群生产者进程在生产产品,并将这些产品提供给消费者进程进行消费,生产者进程和消费者进程可以并发执行,在两者之间设置了一个具有n可缓冲区的缓冲池,生产者进程需要将所生产的产品放到一个缓冲区中,消费者进程可以从缓冲区取走产品消费。


宏观上

  • 生产者往缓冲区 +1
  • 消费者往缓冲区 -1
  • 在生活中这种模型没有问题

微观上

  • 缓冲是在Cache上的
  • 操作缓冲需要三个步骤.

生产者
register=count
register=register+1
count=register

消费者
register=count
register=register-1
count=register

  • 单从生产者程序或消费者程序去看是没问题的
  • 但两者并发执行时就可能出差错

代码实现:

mutex_lock_demo.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <vector>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

int num = 0;

void *producer(void*){
int times = 10000000;
while(times --){
// pthread_mutex_lock(&mutex);
num += 1;
// pthread_mutex_unlock(&mutex);
}
}

void *comsumer(void*){
int times = 10000000;
while(times --){
// pthread_mutex_lock(&mutex);
num -= 1;
// pthread_mutex_unlock(&mutex);
}
}


int main(){
printf("Start in main function.");
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, &producer, NULL);
pthread_create(&thread2, NULL, &comsumer, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("Print in main function: num = %d\n", num);
return 0;
}

Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
export CC=gcc
export CPP=g++
export CFLAGS= -g -lpthread


CSRCS = $(wildcard *.c)
COBJS = $(patsubst %.c, %, $(CSRCS))
CPPSRCS = $(wildcard *.cpp)
CPPOBJS += $(patsubst %.cpp, %, $(CPPSRCS))

OBJ = $(COBJS)
OBJ += $(CPPOBJS)

all: $(OBJ)

%:%.c
$(CC) $^ -o $@ $(CFLAGS)

%:%.cpp
$(CPP) $^ -o $@ $(CFLAGS)

clean:
rm *.o $(OBJ) -rf

.PHONY:clean

哲学家进餐问题

有五个哲学家,他们的生活方式是交替地进行思考和进餐,哲学家们共同使用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子。平时哲学家们只进行思考,饥饿时则试图取靠近他们的左、右两支筷子,只有两支筷子都被他拿到的时候就能进餐,进餐完毕之后,放下左右筷子继续思考。


  • 根源问题是:彼此相互之间没有通信
  • “如果生产者通知消费者我已经完成一件生产”
  • “哲学家向旁边哲学家说我要进餐了”

结论:需要进程间的同步

进程同步解决的问题

  • 对竞争资源在多进程间进行使用次序的协调
  • 使得并发执行的多个进程之间可以有效使用资源和相互合作

进程间同步的原则

临界资源

临界资源指的是一些虽作为共享资源却又无法同时被多个线程共同访问的共享资源。当有进程在使用临界资源时,其他进程必须依据操作系统的同步机制等待占用进程释放该共享资源才可重新竞争使用共享资源

进程间同步的原则

  • 空闲让进:资源无占用,允许使用
  • 忙则等待:资源有占用,请求进程等待
  • 有限等待:保证有限等待时间能够使用资源
  • 让权等待:等待时,进程需要让出CPU

进程同步的方法

  • 消息队列
  • 共享存储
  • 信号量

线程同步

当多个线程并发使用进程资源时,进程内多线程也需要同步

线程同步的方法

  • 互斥量
  • 读写锁
  • 自旋锁
  • 条件变量

Linux的进程管理

Linux进程的相关概念

进程的类型

前台进程

  • 前台进程就是具有终端,可以和用户交互的进程

后台进程

  • 与前台进程相对,没有占用终端的就是后台进程
  • 后台程序基本上不和用户交互,优先级比前台进程低

将需要执行的命令以“&”符号结束

守护进程

  • 守护(daemon)进程是特殊的后台进程
  • 很多守护进程在系统引导的时候启动,一直运行直到系统关闭
  • Linux有很多典型的守护进程

进程的标记

进程ID

  • 进程ID是进程的唯一标记,每个进程拥有不同的ID
  • 进程ID表现为一个非负整数,最大值由操作系统限定

操作系统提供fork函数接口创建进程

父子进程关系可以通过pstree命令查看

ID为0的进程为idle进程,是系统创建的第一个进程
ID为1的进程为init进程,是0号进程的子进程,完成系统初始化
Init进程是所有用户进程的祖先进程

进程的状态标记



操作Linux进程的相关命令

fg/bg命令

  • fg命令将一个后台命令调换至前台终端继续执行
  • bg命令将一个后台暂停的命令变成继续执行
  • ctrl+z将前台工作暂停

jobs命令

  • 查看当前有多少在后台运行的命令

nohup命令

  • 不挂断地运行命令

ps命令

  • ps命令常用于显示当前进程的状态
  • s命令常配合aux参数或ef参数和grep命令检索特定进程

kill命令

  • kill命令发送指定信号给进程
  • kill –l 可以查看操作系统支持的信号

只有(SIGKILL 9)信号可以无条件终止进程,其他信号进程有权忽略

文章作者: hirak0
文章链接: https://hirak0.xyz/posts/61101/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 hirak0's Blog
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论