python的信号量机制

  • 信号通信
一个进程向另一个进程发送一个信号来传递某种信息,接收者根据接收到的信号进行相应的行为

终端命令:
kill -l 查看系统信号
kill -sig PID 向一个进程发送信号

信号介绍:
信号名称		信号含义				默认处理方法
SIGHUP		连接断开
SIGINT		CTRL-C
SIGQUIT		CTRL-\
SIGTSTP		CTRL-Z
SIGKILL		终止一个进程
SIGSTOP		暂停一个进程
SIGALRM		时钟信号
SIGCHID	  子进程状态改变时给父进程发出、
  • python 发送信号
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()

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()
  • 通过signal发送信号完成任务(linux下)
题目:
	司机和售票员的故事:
	× 创建父子进程分别代表司机和售票员
	× 当售票员收到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()
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值