首页 > 系统相关 >进程锁(互斥锁)

进程锁(互斥锁)

时间:2024-01-23 14:34:06浏览次数:33  
标签:__ name number 互斥 进程 ticket data

进程锁(互斥锁)

【一】什么是进程同步(互斥锁)

  • 互斥锁(Mutex)是一种用于多线程编程中控制对共享资源访问的机制。
    • 其作用是保证在同一时刻只有一个线程在访问共享资源,从而避免多个线程同时读写数据造成的问题。
    • 互斥锁的基本原理是在对共享资源进行访问前加锁,使得其他线程无法访问该资源,当访问完成后再解锁,使得其他线程可以进行访问。
    • 通过这种方式,可以保证同一时间只有一个线程在执行关键代码段,从而保证了数据的安全性。
    • 需要注意的是,互斥锁会带来一些额外的开销,

【二】多个进程共享同一打印终端

  • 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,
  • 而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理

【1】未加锁

  • 并发运行,效率高,但竞争同一打印终端,带来了打印错乱
# 并发运行,效率高,但竞争同一打印终端,带来了打印错乱
from multiprocessing import Process, Lock
import time
import os


def work(lock):
    lock.acquire()
    print(f'这是进程:>>>>{os.getpid()} 进程开始')
    time.sleep(2)
    print(f'这是进程 :>>>> {os.getpid()} 进程结束')
    # 走之后把锁放开
    lock.release()


if __name__ == '__main__':
    lock = Lock()
    for i in range(1, 5):
        process = Process(target=work,args=(lock,))
        process.start()
        
# 这是进程:>>>>15252 进程开始
# 这是进程 :>>>> 15252 进程结束
# 这是进程:>>>>34436 进程开始
# 这是进程 :>>>> 34436 进程结束
# 这是进程:>>>>39012 进程开始
# 这是进程 :>>>> 39012 进程结束
# 这是进程:>>>>19524 进程开始
# 这是进程 :>>>> 19524 进程结束
        
    # 总结 : 虽然加锁让我们的程序变成了串行,但是对于整个程序来说,安全
    # 以时间换空间

【2】多个进程共享同一个文件

import json
# 【一】什么是互斥锁
# 互斥锁(Mutex)是一种用于多进程编程中控制对共享资源访问的机制。
# 其作用是保证在同一时刻只有一个线程在访问共享资源,从而避免多个线程同时读写数据造成的问题。
# 互斥锁的基本原理是在对共享资源进行访问前加锁,使得其他线程无法访问该资源,当访问完成后再解锁,使得其他线程可以进行访问。
# 通过这种方式,可以保证同一时间只有一个线程在执行关键代码段,从而保证了数据的安全性。
# 需要注意的是,互斥锁会带来一些额外的开销,

from multiprocessing import Process, Lock
import time
import os

# 【二】多个进程共享同一打印终端
# 【1】未加锁
'''
def work(lock):
    # 进去之前 把门锁起来
    lock.acquire()
    print(f'这是进程 :>>>> {os.getpid()} 进程开始')
    # 模拟 IO 操作
    time.sleep(2)
    print(f'这是进程 :>>>> {os.getpid()} 进程结束')
    # 走之后把锁放开
    lock.release()


if __name__ == '__main__':
    # 声明一把锁
    lock = Lock()
    for i in range(1, 5):
        process = Process(target=work, args=(lock,))
        process.start()
    # 总结 : 虽然加锁让我们的程序变成了串行,但是对于整个程序来说,安全
    # 以时间换空间
'''
# 【三】多个进程共享同一个文件
'''
BASE_DIR = os.path.dirname(__file__)
file_name = 'data.json'
file_path = os.path.join(BASE_DIR, file_name)


# 【一】初始化票数
def save_data(data=None):
    if not data:
        data = {'ticket_number': 2}
    with open(file_path, mode='w') as fp:
        json.dump(data, fp)


# 【二】获取票数信息
def get_ticket_number():
    with open(file_path, 'r') as fp:
        data = json.load(fp)
    return data


# 【三】查看票数
def search_ticket_number(name):
    ticket_data = get_ticket_number()
    print(f'当前用户 {name} 正在查询余票 {ticket_data.get("ticket_number")} ')


# 【四】买票
def buy_ticket(name):
    # 获取票数信息
    ticket_data = get_ticket_number()
    ticket_number = ticket_data.get("ticket_number")
    # 模拟网络延迟
    time.sleep(2)

    # 【2】买票
    if ticket_number > 0:
        # 把票买走,减少库存
        ticket_data['ticket_number'] -= 1
        # 存到文件里
        save_data(data=ticket_data)
        print(f'当前用户 :>>>> {name} 购票成功!')
    else:
        print(f"当前用户 :>>>> {name} 已无余票!")


def main(name):
    # 【1】先让他查票
    search_ticket_number(name=name)
    # 【2】买票
    buy_ticket(name=name)


if __name__ == '__main__':
    save_data()
    task_list = []
    for i in range(1, 5):
        process_obj = Process(target=main, args=(i,))
        process_obj.start()
        task_list.append(process_obj)

    # join 等待
    for process_obj in task_list:
        process_obj.join()
'''

BASE_DIR = os.path.dirname(__file__)
file_name = 'data.json'
file_path = os.path.join(BASE_DIR, file_name)


# 【一】初始化票数
def save_data(data=None):
    if not data:
        data = {'ticket_number': 2}
    with open(file_path, mode='w') as fp:
        json.dump(data, fp)


# 【二】获取票数信息
def get_ticket_number():
    with open(file_path, 'r') as fp:
        data = json.load(fp)
    return data


# 【三】查看票数
def search_ticket_number(name):
    ticket_data = get_ticket_number()
    print(f'当前用户 {name} 正在查询余票 {ticket_data.get("ticket_number")} ')


# 【四】买票
def buy_ticket(name):
    # 获取票数信息
    ticket_data = get_ticket_number()
    ticket_number = ticket_data.get("ticket_number")
    # 模拟网络延迟
    time.sleep(2)

    # 【2】买票
    if ticket_number > 0:
        # 把票买走,减少库存
        ticket_data['ticket_number'] -= 1
        # 存到文件里
        save_data(data=ticket_data)
        print(f'当前用户 :>>>> {name} 购票成功!')
    else:
        print(f"当前用户 :>>>> {name} 已无余票!")


def main(name, lock):
    # 【1】先让他查票
    search_ticket_number(name=name)
    # 买票前加锁
    lock.acquire()
    # 【2】买票
    buy_ticket(name=name)
    # 买票后释放
    lock.release()


if __name__ == '__main__':
    save_data()
    lock = Lock()
    task_list = []
    for i in range(1, 5):
        process_obj = Process(target=main, args=(i, lock))
        process_obj.start()
        task_list.append(process_obj)

    # join 等待
    for process_obj in task_list:
        process_obj.join()

标签:__,name,number,互斥,进程,ticket,data
From: https://www.cnblogs.com/Fredette/p/17982377

相关文章

  • 使用strace将重定向一个已经运行进程的输出
    在Linux上,可以使用以下命令来重定向一个已经运行的进程的输出:首先,找到要重定向输出的进程的PID(进程号)。可以使用命令 ps 或 top 来查看正在运行的进程和它们的PID。使用命令 strace-pPID-s100-ewrite 来跟踪进程的输出。这将列出进程在标准输出上写入的内容......
  • 使用 gdb 调试运行中的 Python 进程(转)
    addbyzhj: 虽然本文是以UbuntuPython2.7为例,但基本也适用于UbuntuPython3,但有两点不同1. aptintallpython<3.x>-dbg,这里的3.x是你要调试的Python程序使用的Python版本。如果你有两个Python程序需要调试,一个使用Python3.7,另一个使用Python3.9,那需要安装python3.7-dbg和pyt......
  • GDB调试之多进程调试 (十八)
    一、调试子进程正常在子进程某处打入断点后,然后执行可以发现,程序并不会在断点处中断下来,而是会继续执行直到程序结束。setfollow-fork-mode它的模式支持两个值,默认的是parent,一个是child;如果是parent的话,那么GDB调试的时候,它就跟着父进程走,就是说默认情况下只能调试主进程也......
  • Linux 文件被进程调用情况下误删文件修复
    具体的原理为:当进程打开了某个文件时,只要该进程保持打开该文件,即使将文件删除,它依然存在于磁盘中。进程并不知道文件已经被删除,它仍然可以通过打开该文件时提供给它的文件描述符进行读取和写入。除了该进程之外,这个文件是不可见的,因为已经删除了其相应的目录索引节点。......
  • 使用多进程库计算科学数据时出现内存错误
    问题背景我经常使用爬虫来做数据抓取,多线程爬虫方案是必不可少的,正如我在使用Python进行科学计算时,需要处理大量存储在CSV文件中的数据。由于每个处理过程需要很长时间才能完成,而您拥有多核处理器,所以您尝试使用多进程库中的Pool方法来提高计算效率。您按照如下方式构建了多......
  • 并发编程之进程通信(生产消费模型)
    什么是生产者消费者模式生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当......
  • 并发编程之多进程理论篇
    引言进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是......
  • 什么是进程/线程/协程
    这实在是一个过于经典的面试题,尤其是对于go开发者来说,毕竟go有协程这种杀手级的东西,面试官就更爱问这个问题了同时网上相关资料很杂,本身这种抽象概念的理解就没有绝对的标准表达,大家领会意思就够了,哈哈,但带来的问题就是查找相关资料的时候容易把自己越看越乱所以此处我写的内容......
  • linux之线程互斥(万字长文详解)
    linux之线程互斥多线程在访问共享资源时的问题假如我们设置一个全局变量!inttickets=1000;//充当有1000张票void*getTicket(void*args){std::stringusername=static_cast<constchar*>(args);while(true){if(tickets>0){......
  • 16-Linux进程管理
    进程的概念:进程是正在执行的一个程序或命令,每一个进程都是一个运行的实体,都有自己的地址空间,并占用一定的系统资源。命令ps:查看当前系统进程状态语法:ps【选项】选项:小技巧:如果想查看进程的CPU占用率和内存占用率,可以使用aux;如果想查看进程的父进程ID可以使用ef案......