ThankNeko's Blog ThankNeko's Blog
首页
  • 操作系统

    • Linux基础
    • Linux服务
    • WindowsServer笔记
    • Ansible笔记
    • Shell笔记
  • 容器服务

    • Docker笔记
    • Kubernetes笔记
    • Git笔记
  • 数据库服务

    • MySQL笔记
    • ELK笔记
    • Redis笔记
  • 监控服务

    • Zabbix笔记
  • Web服务

    • Nginx笔记
    • Tomcat笔记
  • 数据处理

    • Kettle笔记
  • Python笔记
  • Bootstrap笔记
  • C笔记
  • C++笔记
  • Arduino笔记
  • 分类
  • 标签
  • 归档
  • 随笔
  • 关于
GitHub (opens new window)

Hoshinozora

尽人事,听天命。
首页
  • 操作系统

    • Linux基础
    • Linux服务
    • WindowsServer笔记
    • Ansible笔记
    • Shell笔记
  • 容器服务

    • Docker笔记
    • Kubernetes笔记
    • Git笔记
  • 数据库服务

    • MySQL笔记
    • ELK笔记
    • Redis笔记
  • 监控服务

    • Zabbix笔记
  • Web服务

    • Nginx笔记
    • Tomcat笔记
  • 数据处理

    • Kettle笔记
  • Python笔记
  • Bootstrap笔记
  • C笔记
  • C++笔记
  • Arduino笔记
  • 分类
  • 标签
  • 归档
  • 随笔
  • 关于
GitHub (opens new window)
  • Python笔记

    • 基础知识

    • 类与面向对象

    • 并发编程

      • 并发相关介绍
      • 多进程与进程间通信
      • 多线程与线程间通信
      • 其他锁与队列
        • 死锁现象
        • 递归锁
        • 信号量
        • 线程的Event事件
        • LifoQueue队列
        • PriorityQueue
      • 网络IO模型与协程
    • Web编程

    • 模块笔记

    • 其他

  • C笔记

  • C++笔记

  • Arduino笔记

  • Dev
  • Python笔记
  • 并发编程
Hoshinozora
2023-02-25
目录

其他锁与队列

# 死锁现象

# 介绍

  • B锁在线程1上,A锁在线程2上,他们两个互相等待对方释放锁,于是就出现了死锁现象
  • 所以互斥锁应该谨慎的使用,防止出现死锁现象

# 例子

from threading import Thread, Lock
import time
mutexA = Lock()
mutexB = Lock()
class task(Thread):
    def run(self):
        self.task1()
        self.task2()
    def task1(self):
        mutexA.acquire()
        print("{} 抢到了A锁!".format(self.name))
        mutexB.acquire()
        print("{} 抢到了B锁!".format(self.name))
        mutexA.release()
        mutexB.release()
    def task2(self):
        mutexB.acquire()
        print("{} 抢到了B锁!".format(self.name))
        time.sleep(2)
        mutexA.acquire()
        print("{} 抢到了A锁!".format(self.name))
        mutexA.release()
        mutexB.release()
if __name__ == "__main__":
    for i in range(2):
        t = task()
        t.start()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27


# 递归锁

# 介绍

  • 递归锁可以被第一个抢到锁的进程或线程,连续的acquire和release
  • 它的内部有一个计数器,每acquire一次计数加一,每release一次计数减一
  • 只有当计数重新为0时,它才会被真正释放,此时其他进程或线程才能抢到锁

# 使用方法

# 导入线程递归锁(另外多进程模块也有递归锁)
from threading import Thread, RLock
# 加锁、释放锁的方法和互斥锁一样
# 不同的是,只有锁重新为0,也就是加多少次锁,就释放多少次锁,锁才会被真正的释放
def task():
    mutex.acquire()
    print("{} 抢到锁,锁+1!".format(current_thread().name))
    mutex.acquire()
    print("{} 锁+1!".format(current_thread().name))
    mutex.release()
    print("{} 锁-1!".format(current_thread().name))
    mutex.release()
    print("{} 锁为0!".format(current_thread().name))

1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 使用例子

from threading import Thread, RLock,current_thread
mutex = RLock()
def task():
    mutex.acquire()
    print("{} 抢到锁,锁+1!".format(current_thread().name))
    mutex.acquire()
    print("{} 锁+1!".format(current_thread().name))
    mutex.release()
    print("{} 锁-1!".format(current_thread().name))
    mutex.release()
    print("{} 锁为0!".format(current_thread().name))
if __name__ == "__main__":
    t_list = []
    for i in range(3):
        t = Thread(target=task)
        t.start()
        t_list.append(t)
    
    for t in t_list:
        t.join()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20


# 信号量

# 介绍

  • 信号量在不同的阶段对应不同的技术点
  • 在并发编程中,信号量是锁,可以被多个进程或线程同时抢到的锁,可以指定这把锁能被多少进程或线程同时持有
  • 除此之外,其他的和互斥锁一样,也是要释放锁,其他没有锁的线程才能抢锁执行

# 使用方法

# 导入信号量(另外多进程模块也有信号量)
from threading import Thread, Semaphore

# Semaphore(9)是指锁最多同时被9个线程持有
# 第10个如果要执行,就得等待前面拿到锁的线程释放锁,然后抢锁
mutex = Semaphore(9)
def task():
    mutex.acquire()
    print('{} 抢到锁!'.format(current_thread().name))
    mutex.release()
1
2
3
4
5
6
7
8
9
10

# 使用例子

from threading import Thread, Semaphore, current_thread
import time
mutex = Semaphore(9)
def task():
    mutex.acquire()
    print('{} 抢到锁!'.format(current_thread().name))
    time.sleep(2)
    mutex.release()
t_list = []
for i in range(10):
    t = Thread(target=task)
    t.start()
    t_list.append(t)
- 此处由于第10个线程时,锁已经被抢完了,所以要等待2秒前面的线程释放锁,才能抢锁执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14


# 线程的Event事件

# 介绍

  • 线程或进程中的event事件,用于控制其他子进程或子线程的执行状态
  • 比如线程1用于控制线程2执行,线程2会阻塞等待事件开始
  • 当线程1使用set方法时,事件开始,线程2会跳出停止阻塞继续执行

# 使用例子

- from threading import Thread, Event
import time
event = Event()
def task():
    print('任务暂停!')
    time.sleep(2)
    print('任务开始!')
    event.set()
def nijia():
    print('等待任务开始!')
    event.wait()
    print('nijia开始执行任务!')
t1 = Thread(target=task)
t2 = Thread(target=nijia)
t1.start()
t2.start()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16


# LifoQueue队列

# 介绍

  • 队列是管道 + 锁,虽然线程是数据共享,但使用Queue可以使数据操作更安全
  • 除了先进先出的队列,还有后进先出的队列,就是LifoQueue队列(堆栈)
  • 就像叠衣服,从下往上叠上去,从上往下取出来

# 使用方法

# 导入模块中的类
from queue import LifoQueue
# 除了后进先出,使用方法和普通队列一样
q = LifoQueue()
q.put(1)
q.put(2)
print(q.get())
print(q.get())
1
2
3
4
5
6
7
8


# PriorityQueue

# 介绍

  • PriorityQueue是优先级队列,与普通队列不同的是,在插入数据时,我们需要指定优先级
    • put括号内放入一个元组,元组的第一个下标的数值表示优先级,第二个表示要插入的值 (设置的优先级数值越小,优先级越高)
  • 在取数据时,无论先后顺序,它都会优先取优先级高的数据
  • 如果是同优先级,则是按先进先出的原则

# 使用方法

# 导入模块中的类
from queue import LifoQueue
q = PriorityQueue()
q.put((-1,'111'))
q.put((0,'222'))
q.put((0,'333'))
print(q.get())
print(q.get())
print(q.get())
1
2
3
4
5
6
7
8
9
#死锁现象#递归锁#信号量#Event事件
多线程与线程间通信
网络IO模型与协程

← 多线程与线程间通信 网络IO模型与协程→

最近更新
01
二〇二五年四月十七日随笔
04-17
02
二〇二五年四月十六日随笔
04-16
03
二〇二五年四月九日随笔
04-09
更多文章>
Theme by Vdoing | Copyright © 2022-2025 Hoshinozora | MIT License
湘ICP备2022022820号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式