什么是进程通讯的信号?
用过Windows的我们都知道,当我们无法正常结束一个程序时,可以用任务管理器强制结束这个进程,但这其实是怎么实现的呢?同样的功能在Linux上是通过生成信号和捕获信号来实现的,运行中的进程捕获到这个信号然后作出一定的操作并最终被终止。信号是UNIX和Linux系统响应某些条件而产生的一个事件,接收到该信号的进程会相应地采取一些行动。通常信号是由一个错误产生的。但它们还可以作为进程间通信或修改行为的一种方式,明确地由一个进程发送给另一个进程。一个信号的产生叫生成,接收到一个信号叫捕获
什么是线程锁?
1.在单一进程的情况下可以叫单进程也可以叫单线程
2.
线程锁的大致思想是:如果线程A和线程B会执行实例的两个函数a和b
set,直到A执行完a函数再把B从wait set中激活。这样就保证了B必定在A之后运行,无论在之前它们的时间先后顺序是怎样的。
3.
线程锁用于必须以固定顺序执行的多个线程的调度
线程锁的思想是先锁定
后序
线程,然后让
线序
线程完成任务再解除对
后序
线程的锁定。
信号:
一个
进程通过信号的方式
传递某种
讯息,
接收方收到信号
后作出相应的处理
kill -sig pid:通过pid发送信号
杀死指定进程
kill -l:
查看操作系统内所所有sig信号
关于信号:
信号名称: 系统定义,名字或数字
信号含义:系统定义,信号的作用
默认处理方法:
当一个进程
接收到信号时,
默认产生的效果
进程
终止、
暂停进程、
忽略法发生
SIGHUP: 断开链接
SIGINT: Ctrl + c
SIGQUIT: Ctrl + \
SIGTSTP : Ctrl + z
SIGKILL: 终止进程且不能被处理
SIGSTOP: 暂停进程且不能被处理
SIGALRM: 时钟信号
SIGCHLD: 子进程改变状态时父进程会收到此信号
Python信号处理:(
signal模块)
os.kill(pid,sig)
功能:
发送一个
信号给某个进程
参数:
pid:给那个进程发送信号(进程pid)
sig:要发送的信号类型
signal.alarm(sec)
功能:
异步执行
设置时钟信号
在
一定时间后给自己发送一个SIGALRM
信号
一个进程只能挂起一个时钟
重新挂起时钟会
覆盖之前时钟
参数:
sec:时间(秒)
signal.pause()
功能:
阻塞进程,
等待一个
信号
signal.signal(sig,handler)
功能:
信号处理
参数:
sig:要处理的信号
handler:信号
处理方法
可选值:
SIG_DFL 表示使用
默认方法处理
SIG_IGN 表示
忽略这个信号
func
自定义函数
自定义函数格式:
def func(sig,frame):
sig:收到的信号
frame:信号结构对象
signal函数也
是一个
异步处理
函数,只要执行了该函数
则进程
任意时候接受到相应的信号都会处理
signal是
不能处理SIGKILL 、SIGSTOP的
父进程中可以使用 signal(
SIGCHLD,SIG_IGN)
将
子进程的
退出交给系统处理
程序的异步和同步执行:
(
单进程的同步异步)
同步:
程序
按照步骤一步步执行,呈现一个
先后性的顺序
异步:
信号是唯一一个内部通信方式
程序在执行中
利用内核功能
帮助完成必要的辅助操作
不影响应用层的
持续执行
信号是一种异步的进程间通讯方法
示例:
from signal import *
import time
def handler(sig,frame): # 自定义处理信号
if sig == SIGALRM: # 判断信号类型
print("收到时钟信号")
elif sig == SIGINT:
print("就不结束 略略略~")
alarm(5) # 设置5秒时钟信号
signal(SIGALRM,handler)
signal(SIGINT,handler) # Ctrl + C
while True:
print("Waiting for a signal")
time.sleep(2)
信号量:
给定
一定的数量,对多个进程可见,
并且多个进程根据信号量的多少确定不同行为
sem = Semaphore(num)
功能:
创建信号量
参数:信号量初始值
返回值:信号量对象
sem.acquire()
将信号数量
减1 当数量为
0时阻塞
sem.release()
将信号量
加1
sem.get_value()
获取当前信号量的值(
数量)
同步互斥机制
目的:
解决对
共有资源产生的资源
争夺
临界资源:
多个进程或线程
都可以操作的资源
临界区:
操作临界资源的代码段
同步:
同步
是一种
合作关系,为完成某个任务,
多
进程或者多个
线程之间形成
的一种协调
按照约定执行,相互告知,共同完成任务
互斥:
互斥
是一种
制约关系,当一个
进程或者
线程
进入临界区操作资源时采用上锁的方式,
阻止其他进程
操作,直到
解锁后才能让出资源
Event事件:
from multiprocessing
import Event
创建事件对象
e = Event()
事件
阻塞
e.wait([timeout])
功能:
使进程处于
阻塞状态,
直到事件对象被set
事件
设置:
e.set.()
功能:
让事件对象
变为被设置状态
清除设置:
e.clear()
功能:使事件对象
清除设置状态
事件
判断:
e.is_set()
判断当前事件
是否被set
示例:
from multiprocessing import Process,Event
from time import sleep
def wait_event(file):
print("准备操作临界资源")
e.wait() # 等待主进程执行结束后set
print("开始操作临界资源",e.is_set())
fw = open('1.jpg','wb')
with open(file,'rb') as f: # 复制图片
fw.write(f.read())
def wait_event_timeout(file):
print("也想操作临界资源")
e.wait(2) # 等待主进程执行set并进行2秒超时检测
if e.is_set():
print("也开始操作临界资源")
fw = open('2.jpg','wb')
with open(file,'rb') as f: # 复制图片
fw.write(f.read())
else:
print("等不了了,不等了")
# 创建事件
e = Event()
path = "/home/tarena/file.jpg"
file = 'file.jpg'
# 创建两个进程分别复制两个图片
p1 = Process(target = wait_event,args = (file,))
p2 = Process(target = wait_event_timeout,args = (file,))
p1.start()
p2.start()
# 主进程先复制图片 让子进程进入wait状态
print("主进程在操作临界资源")
sleep(3)
fw = open(file,'wb')
with open(path,'rb') as f:
fw.write(f.read())
fw.close()
e.set() # 子进程set
print("主进程操作完毕")
p1.join()
p2.join()
锁 Look
multiprocessing -->
Look
创建对象:
Lock = Lock()
lock.acquire()
上锁
lock.release()
解锁
如果一个锁对象
已经被上锁再
调用则
会阻塞
multiprocessing 创建的子进程不能用input 会报错
示例:
from multiprocessing import Process,Lock
import sys
from time import sleep
#sys.stdout作为标准输出流是多个进程共有的资源
def writer1():
lock.acquire() #上锁
for i in range(5):
sleep(1)
sys.stdout.write("writer1输出\n")
lock.release() #解锁
# 虽然都sleep1秒但是 若不加锁会每1秒打印两次
# 由于上锁原因 w1执行完临界区w2才能被执行 一秒一次
def writer2():
with lock:
for i in range(5):
sleep(1)
sys.stdout.write("writer2输出\n")
#创建锁
lock = Lock()
w1 = Process(target = writer1)
w2 = Process(target = writer2)
w1.start()
w2.start()
w1.join()
w2.join()
多线程:
什么是线程(
thread)
线程也是一种
多任务编程方式,可以使用计算机的多核资源
线程被
称为轻量级的进程
线程的特征:
1.
一个进程可以
包含
多个线程
2.线程是计算机
内核使用的最小单位
3.线程也是一个
运行过程,也要
消耗计算机
资源
4.多个
线程共享共用
进程的资源
5.线程也
有自己的
特征属性,
TID、
指令集、
线程栈
6.多个线程之间
独立运行互不干扰 空间不独立(都消耗进程空间)
7.线程的
创建删除消耗的资源要
小于进程 线程/进程(
1/20)
threading 模块
threshold.Thread()
功能:
创建线程对象
参数:
target 线程
函数
name 线程名 默认为
Thread-1...
args
元组给线程函数位置传参
kwargs
字典给线程函数键值传参
返回值:
线程对象
t.start()
启动线程
t.join()
回收线程
线程对象属性:
t.
name 线程名
t.
setName()
设置线程名称
t.
is_alive()
查看线程
状态
threading.
currentThread()
获取当前进程对象
t.
daemon属性
默认False主线程的退出不会影响分支线程的执行
设置为
True时主线程退出分支线程也退出
设置daemon值
t.setDaemon(True)
t.daemon = True
查看daemon值
t.isDaemon
创建自己的线程类;
1.继承Thread
2.加载父类__init__
3.重写run
示例:
from threading import Thread
from time import sleep, ctime
# 创建一个MyThread类继承Thread
class MyThread(Thread):
def __init__(self, target, name = "Tedu", args = (), kwargs = {}):
super().__init__() # 重新加载父类的__init__初始化方法
self.target = target
self.name = name
self.args = args
self.kwargs = kwargs
def run(self): # 在创建对象时自动调用run方法
# 在调用run时调分支线程要执行的线程函数 以*元组和**字典的方式接收万能传参
self.target(*self.args, **self.kwargs)
#线程函数
def player(song,sec):
for i in range(2):
print("Playing %s : %s"%(song, ctime()))
sleep(sec)
# 用自定义类创建线程并执行
t = MyThread(target = player, args = ("卡路里", 3))
t.start()
t.join()