zoukankan      html  css  js  c++  java
  • 僵尸进程与孤儿进程 互斥锁 进程之间的通信

    僵尸进程与孤儿进程

    基于unix环境(linux, macOS)

    ​ 主进程需要等待子进程结束之后, 主进程才结束

    主进程时刻监测子进程的运行状态, 当子进程结束之后, 一段时间之内, 将子进程进行回收

    为什么主进程不在子进程结束后马上对其回收呢?

    ​ 主进程与子进程是异步关系, 主进程无法马上捕获子进程什么时候结束

    ​ 如果子进程结束之后, 马上在内存中释放资源, 主进程就没有办法监测子进程的状态了

    unix针对于上面的问题, 提供了一个机制

    ​ 所有的子进程结束之后, 立马会释放掉文件的操作链接, 内存的大部分数据, 但是会保留一些内容: 进程号, 结束时间, 运行状态. 等待主进程监测, 回收.

    僵尸进程

    ​ 所有的子进程结束之后, 在被主进程回收之前, 都会进入僵尸进程状态

    僵尸进程有无危害

    ​ 如果父进程不对僵尸进程进行回收(wait/waitpid), 产生大量的僵尸进程, 这样就会占用内存, 占用进程pid号

    僵尸进程如何解决

    ​ 父进程产生了大量子进程, 但是不回收, 这样就会形成大量的僵尸进程, 解决方式就是直接杀死父进程, 将所有的僵尸进程变成孤儿进程, 由init进行回收

    孤儿进程

    ​ 父进程由于某种原因结束了, 但是你的子进程还在运行中, 这样你的这些子进程就成了孤儿进程, 你的父进程如果结束了, 你的所有的孤儿进程就会被init进程的回收, init就变成了你的父进程, 对你进行回收

    互斥锁

    ​ 三个同事, 同时用一个打印机打印内容.

    ​ 三个进程模拟三个同事, 输出平台模拟打印机.

    ​ 互斥锁:

    ​ 可以公平性的保证顺序以及数据的安全

    # 版本一
    from multiprocessing import Process
    import time
    import random
    import os
    
    
    def task1():
        print(f"{os.getpid()}开始打印了")
        time.sleep(random.randint(1, 3))
        print(f"{os.getpid()}打印结束了")
    
    
    def task2():
        print(f"{os.getpid()}开始打印了")
        time.sleep(random.randint(1, 3))
        print(f"{os.getpid()}打印结束了")
    
    
    def task3():
        print(f"{os.getpid()}开始打印了")
        time.sleep(random.randint(1, 3))
        print(f"{os.getpid()}打印结束了")
    
    
    if __name__ == '__main__':
        p1 = Process(target=task1)
        p2 = Process(target=task2)
        p3 = Process(target=task3)
    
        p1.start()
        p2.start()
        p3.start()
    
    """
    188412开始打印了
    188408开始打印了
    188388开始打印了
    188412打印结束了
    188388打印结束了
    188408打印结束了
    """
    
    # 现在是所有的进程都并发的抢占打印机,
    # 并发是以效率优先的, 但是目前我们的需求: 顺序优先
    # 多个进程共抢一个资源时, 要保证顺序优先: 串行, 一个一个来
    
    # 版本二
    from multiprocessing import Process
    import time
    import random
    import os
    
    
    def task1():
        print(f"{os.getpid()}开始打印了")
        time.sleep(random.randint(1, 3))
        print(f"{os.getpid()}打印结束了")
    
    
    def task2():
        print(f"{os.getpid()}开始打印了")
        time.sleep(random.randint(1, 3))
        print(f"{os.getpid()}打印结束了")
    
    
    def task3():
        print(f"{os.getpid()}开始打印了")
        time.sleep(random.randint(1, 3))
        print(f"{os.getpid()}打印结束了")
    
    
    if __name__ == '__main__':
        p1 = Process(target=task1)
        p2 = Process(target=task2)
        p3 = Process(target=task3)
    
        p1.start()
        p1.join()
        p2.start()
        p2.join()
        p3.start()
        p3.join()
    
    """
    160876开始打印了
    160876打印结束了
    188264开始打印了
    188264打印结束了
    188328开始打印了
    188328打印结束了
    """
    
    # 我们利用join, 解决串行的问题, 保证了顺序优先, 但是这个谁先谁后是固定的.
    # 这样不合理, 你在争抢同一个资源的时候, 应该是先到先得, 保证公平
    
    # 版本三
    from multiprocessing import Process
    from multiprocessing import Lock
    import time
    import random
    
    
    def task1(p, lock):
        lock.acquire()
        print(f"{p}开始打印了")
        time.sleep(random.randint(1, 3))
        print(f"{p}打印结束了")
        lock.release()
    
    def task2(p, lock):
        lock.acquire()
        print(f"{p}开始打印了")
        time.sleep(random.randint(1, 3))
        print(f"{p}打印结束了")
        lock.release()
    
    
    def task3(p, lock):
        lock.acquire()
        print(f"{p}开始打印了")
        time.sleep(random.randint(1, 3))
        print(f"{p}打印结束了")
        lock.release()
    
    
    if __name__ == '__main__':
    
        mutex = Lock()
        p1 = Process(target=task1, args=("p1", mutex))
        p2 = Process(target=task2, args=("p2", mutex))
        p3 = Process(target=task3, args=("p3", mutex))
    
        p1.start()
        p2.start()
        p3.start()
    
    """
    p1开始打印了
    p1打印结束了
    p2开始打印了
    p2打印结束了
    p3开始打印了
    p3打印结束了
    """
    

    lock 与 join 的区别

    共同点

    ​ 都可以把并发变成串行, 保证了顺序

    不同点

    ​ join 认为设定顺序, lock 让其争抢顺序, 保证了公平性

    进程之间的通信

    ​ 进程在内存级别是隔离的, 但是文件在磁盘上

    1.基于文件通信

    ​ 利用抢票系统讲解

    # 抢票系统
    # 1. 先可以查票, 查询余票数.    并发
    # 2. 进行购买, 向服务端发送请求, 服务端接收请求, 在后端将票数-1, 返回到前端           串行
    from multiprocessing import Process
    import json
    import time
    import os
    import random
    
    
    def search():
        time.sleep(random.randint(1, 3))   # 模拟网络延迟(查询环节)
        with open("ticket.json", "r", encoding="utf-8")as f:
            dic = json.load(f)
            print(f"{os.getpid()}查看了票数, 剩余{dic['count']}")
    
    
    def paid():
        with open("ticket.json", "r", encoding="utf-8")as f:
            dic = json.load(f)
            if dic["count"] > 0:
                dic["count"] -= 1
                time.sleep(random.randint(1, 3))
                with open("ticket.json", "w",  encoding="utf-8")as f1:
                    json.dump(dic, f1)
                print(f"{os.getpid()} 购买成功")
    
    
    def task():
        search()
        paid()
        
    if __name__ == '__main__':
    
        for i in range(6):
            p = Process(target=task)
            p.start()
    
    # 当多个进程共抢一个数据时, 如果要保证数据的安全, 必须要串行.
    # 要想让购买环节进行串行, 我们必须要加锁处理
    
    from multiprocessing import Process
    from multiprocessing import Lock
    import json
    import time
    import os
    import random
    
    
    def search():
        time.sleep(random.randint(1, 3))
        with open("ticket.json", encoding="utf-8")as f:
            dic = json.load(f)
            print(f"{os.getpid()} 查看了票数, 剩余{dic['count']}")
    
    
    def paid():
        with open("ticket.json", encoding="utf-8")as f:
            dic = json.load(f)
        if dic["count"] > 0:
            dic["count"] -= 1
            time.sleep(random.randint(1, 3))
            with open("ticket.json", "w", encoding="utf-8")as f1:
                json.dump(dic, f1)
            print(f"{os.getpid()}购买成功")
    
    
    def task(lock):
        search()
        lock.acquire()
        paid()
        lock.release()
    
    if __name__ == '__main__':
        mutex = Lock()
        for i in range(6):
            p = Process(target=task, args=(mutex,))
            p.start()
    """
    203496 查看了票数, 剩余3
    203512 查看了票数, 剩余3
    203496购买成功
    203504 查看了票数, 剩余2
    203480 查看了票数, 剩余2
    203488 查看了票数, 剩余2
    203520 查看了票数, 剩余2
    203512购买成功
    203504购买成功
    """
    
    # 当很多进程共抢一个资源(数据)时, 你要保证顺序(数据的安全), 一定要串行. 
    # 互斥锁: 可以公平性的保证顺序以及数据的安全
    # 基于文件的进程之间的通信:
    		# 效率低
            # 自己加锁麻烦而且很容易出现死锁
    

    2.基于队列通信

    3.基于管道通信

  • 相关阅读:
    UVa OJ 148 Anagram checker (回文构词检测)
    UVa OJ 134 LoglanA Logical Language (Loglan逻辑语言)
    平面内两条线段的位置关系(相交)判定与交点求解
    UVa OJ 130 Roman Roulette (罗马轮盘赌)
    UVa OJ 135 No Rectangles (没有矩形)
    混合函数继承方式构造函数
    html5基础(第一天)
    js中substr,substring,indexOf,lastIndexOf,split等的用法
    css的textindent属性实现段落第一行缩进
    普通的css普通的描边字
  • 原文地址:https://www.cnblogs.com/beichen123/p/11391594.html
Copyright © 2011-2022 走看看