一个进程向另一个进程发送一个信号来传递某种信息,接收者根据接收到的信号进行相应的行为
终端命令:
kill -l 查看系统信号
kill -sig PID 向一个进程发送信号
信号介绍:
信号名称 信号含义 默认处理方法
SIGHUP 连接断开
SIGINT CTRL-C
SIGQUIT CTRL-\
SIGTSTP CTRL-Z
SIGKILL 终止一个进程
SIGSTOP 暂停一个进程
SIGALRM 时钟信号
SIGCHID 子进程状态改变时给父进程发出、
signal、os模块
os.kill(pid,sig)
功能:发送信号
参数: pid 目标进程
signal.alarm(sec)
功能:向自身发送时钟信号 --> SIGALRM
参数:sec 时钟时间
* 进程中只能有一个时钟,第二个会覆盖第一个时间
同步执行:按照顺序逐句执行,一步完成再做下一步
异步执行:再执行过程中利用内核记录延迟发生或者准备处理的事件,这样不影响应用层的持续执行,当事件发生时再由内核告知应用层处理
* 信号是唯一的异步通信方法
signal.pause()
功能:阻塞等待接收一个信号
signal.signal(signum,handler)
功能:处理信号
参数:signum 要处理的信号
handler 信号的处理方法:
SIG_DFL 表示使用默认的方法处理
SIG_IGN 表示忽略这个信号
func 传入一个函数,表示用指定函数处理
函数格式要求:def func(sig,frame)
sig: 捕获到的信号
frame: 信号对象
from signal import *
import time
#信号处理函数
def handler(sig,frame):
if sig == SIGALRM:
print('接受到时钟信号')
elif sig == SIGINT:
print('接受到CTRL-C')
#def CTRL_C(sig,frame):
# print('接收到CTRL-C')
alarm(5)
signal(SIGALRM,handler)
#signal(SIGINT,CTRL_C) 使用CTRL_C函数处理信号
signal(SIGINT,handler)
while True:
time.sleep(2)
print('Wating for a signal')
原理:给定一个数量,对多个进程可见,且多个进程都可以操作。进程通过对数量多少的判断执行各自的行为。(生产者/消费者)
multiprocessing --> Semaphore()
sem = Semaphore(num)
功能:创建信号量
参数:信号量初始值
返回:信号量对象
sem.get_value() 获取信号量值
sem.acquire() 将信号量减1 当信号量为0时会阻塞
sem.release() 将信号量加1
#演示信号量的创建和方法
from multiprocessing import Semaphore,Process
from time import sleep
import os
#创建信号量
sem = Semaphore(3)
def fun():
print('进程{}等待信号量'.format(os.getpid()))
#消耗一个信号量
sem.acquire() # 为0则阻塞
print('进程{}消耗一个信号量'.format(os.getpid()))
sleep(3)
sem.release()
print('进程{}添加一个信号量'.format(os.getpid()))
jobs = []
for i in range(4):
p = Process(target = fun)
jobs.append(p)
p.start()
for i in jobs:
i.join()
print(sem.get_value())
临界资源:多个进程后者线程都能够操作的共享资源
临界区:操作临界资源的代码段
同步:同步是一种合作关系,为完成某个任务,多进程或者多线程之间形成一种协调,按照约定或条件执行操作临界资源。
互斥:互斥是一种制约关系,当一个进程或者线程使用临界资源时进行上锁处理,当另一个进程使用时会阻塞等待,直到解锁后才能继续使用。
multiprocessing --> Event
创建事件对象
e = Event()
设置事件阻塞
e.wait([timeout])
事件设置 当事件被设置后e.wait()不再阻塞
e.set()
清除设置 当事件设置被clear后 e.wait又会阻塞
e.clear()
事件状态判断
e.is_set()
- 通过event事件实现父子进程分别读取文件的前后部分
#使用父子进程分别将文件的前后两半部分读取到一个文件中
from multiprocessing import Process,Event
import os
#获取读文件的大小
size = os.path.getsize('file')
def son_process():
print('子进程等待进入临界区')
e.wait()
fr = open('file','r')
fw = open('file2','a') # 以追加方式打开文件
n = size//2
fr.seek(n,0) # 将游标设置到读文件的一半
#读取后半部分文件
while True:
if n < 1024:
data = fr.read(n)
fw.write(data)
break
data = fr.read(1024)
fw.write(data)
n -= 1024
fr.close()
fw.close()
print('子进程释放临界区')
e = Event()
p1 = Process(target = son_process)
p1.start()
#父进程读取文件的前半部分
fr = open('file','r')
fw = open('file2','w')
n = size // 2
while True:
if n < 1024:
data = fr.read(n)
fw.write(data)
break
data = fr.read(1024)
fw.write(data)
n -= 1024
fw.close()
fr.close()
e.set()
p1.join()
创建对象
lock = Lock()
lock.acquire() 上锁,如果锁已经是上锁状态调用此函数会阻塞
lock.release() 解锁
with lock: 上锁
......
......
解锁
#演示锁互斥使用终端输出
from multiprocessing import Process,Lock
import sys
#两个进程都要进行锁的约束
def writer1():
lock.acquire()
for i in range(20):
sys.stdout.write('Writer1想先向终端写入\n')
lock.release()
def writer2():
with lock:
for i in range(20):
sys.stdout.write('Writer2想先向终端写入\n')
lock = Lock()
w1 = Process(target = writer1)
w2 = Process(target = writer2)
w1.start()
w2.start()
w1.join()
w2.join()
题目:
司机和售票员的故事:
× 创建父子进程分别代表司机和售票员
× 当售票员收到SIGINT信号,给司机发送SIGUSR1信号此时司机打印'老司机发车了'
× 当售票员收到SIGQUIT信号,给司机发送SIGUSR2信号此时司机打印'车速有点快,系好安全带'
× 当司机捕捉到SIGTSTP信号,给售票员发送SIGUSR1,售票员打印'到站了,请下车'
× 到站后,售票员先下车,司机下车(子进程先退出)
说明:SIGINT SIGQUIT SIGTSTP从键盘发出
# -*- coding:UTF-8 -*-
from multiprocessing import Process
import os
from signal import *
from time import sleep
def saler_handler(sig,frame):
if sig == SIGINT:
os.kill(os.getppid(),SIGUSR1)
elif sig == SIGQUIT:
os.kill(os.getppid(),SIGUSR2)
elif sig == SIGUSR1:
print('到站了,请下车')
os._exit(0) # 子进程退出,可不写
#子进程代表售票员
def saler():
signal(SIGINT,saler_handler)
signal(SIGQUIT,saler_handler)
signal(SIGUSR1,saler_handler)
signal(SIGTSTP,SIG_IGN)
while True:
sleep(2)
print('python带你去远方')
def driver_handler(sig,frame):
if sig == SIGUSR1:
print('老司机开车了')
elif sig == SIGUSR2:
print('车速有点快,系好安全带')
elif sig == SIGTSTP:
os.kill(p.pid,SIGUSR1)
p = Process(target = saler)
p.start()
#父进程
signal(SIGUSR1,driver_handler)
signal(SIGUSR2,driver_handler)
signal(SIGTSTP,driver_handler)
signal(SIGINT,SIG_IGN)
signal(SIGQUIT,SIG_IGN)
p.join()