线程锁

问题现象: 多线程情况下,CPU遇到阻塞会进行线程的切换,所以导致执行了tmp-=1的值还未赋值给num=tmp,另一个线程2又开始了tmp -=1,所以导致最后的值重复赋值给了num,所以出现了final num非0 的情况。[time.sleep(0.000.) 休息的时间越短,最后的值越小]

import time
import threading
def addNum():
global num #在每个线程中都获取这个全局变量
temp=num
print('--get num:',num )
time.sleep(0.00000001)
temp -= 1
num = temp
num = 100 #设定一个共享变量
thread_list = []
lock=threading.Lock()
for i in range(100):
t = threading.Thread(target=addNum)
t.start()
thread_list.append(t)
for t in thread_list: #等待所有线程执行完毕
t.join()
print('final num:', num )

问题解决:同步锁

锁的分类:

同步锁:确保每一时刻有一个线程使用共享资源,避免脏数据的产生

死  锁 :线程相互之间等待释放

递归锁:有内部计时器和锁组成,可以重复利用,每利用一次count+1,释放一次-1

同步锁:

lock.acquire()   # 获得锁

lock.release()  # 释放锁

import threading
def addNum():
global num #在每个线程中都获取这个全局变量
# num-=1
lock.acquire() # 获得锁
temp=num
print('--get num:',num )
#time.sleep(0.1)
num =temp-1 #对此公共变量进行-1操作
lock.release() # 释放锁
num = 100 #设定一个共享变量
thread_list = []
lock=threading.Lock()
for i in range(100):
t = threading.Thread(target=addNum)
t.start()
thread_list.append(t)
for t in thread_list: #等待所有线程执行完毕
t.join()
print('final num:', num )

[线程分析---图片来自网络]

死锁: AB同时锁住了,等待对方释放锁

解决办法:使用递归锁

import time
import threading
class MyThread(threading.Thread):
def doA(self):
lockA.acquire()
print(self.name, "gotlockA", time.ctime())
time.sleep(3)
lockB.acquire()
print(self.name, "gotlockB", time.ctime())
lockB.release()
lockA.release()
def doB(self):
lockB.acquire()
print(self.name,"gotlockB",time.ctime())
time.sleep(2)
lockA.acquire()
print(self.name,"gotlockA",time.ctime())
lockA.release()
lockB.release()
def run(self):
self.doA()
self.doB()
if __name__ == '__main__':
lockA = threading.Lock()
lockB = threading.Lock()
threads = []
for i in range(5):
threads.append(MyThread())
for i in threads:
i.start()
for i in threads:
i.join()

递归锁: 可以重复利用的锁  [计时器 + 锁]

import time
import threading
class MyThread(threading.Thread):
def doA(self):
lock.acquire() # 执行一个操作,用一个锁锁住线程
print(self.name, "gotlockA", time.ctime())
time.sleep(3)
lock.acquire() # 执行一个操作,用一个锁锁住线程
print(self.name, "gotlockB", time.ctime())
lock.release()
lock.release()
def doB(self):
lock.acquire()
print(self.name,"gotlockB",time.ctime())
time.sleep(2)
lock.acquire()
print(self.name,"gotlockA",time.ctime())
lock.release()
lock.release()
def run(self):
self.doA()
self.doB()
if __name__ == '__main__':
lock = threading.RLock()
threads = []
for i in range(5):
threads.append(MyThread())
for i in threads:
i.start()
for i in threads:
i.join()

问:为什么RLock里面还有一个Rlock? 

答:1.防止其他的函数调用数据操作的函数,造成2个数据在进行写操作,产生脏数据

2.减少了其他函数中为了避免产生脏数据而做重复的锁操作

import time
import threading
class Account:
def __init__(self, money, id):
self.account = id
self.balance = money
self.r = threading.RLock() # 这里应该是每个都有自己的锁 def add(self, num): # 2 可以在方法上添加一个锁来解决其他函数调用方法造成脏数据的问题
self.r.acquire()
self.balance += num
self.r.release()
def adwithdrd(self, num):
self.r.acquire()
self.balance -= num
self.r.release()
# def diy(self, num): # 3也是类中的重复调用,这也就是为什么会有Rlock的重复调用了
# self.r.acquire()
# self.balance -= num
# self.adwithdrd(num)
# self.r.release()
def __str__(self):
print(self.balance, self.account)
a1 = Account(500, 'A')
b1 = Account(300, 'B')
# def user_trans(A, B, num):
# A.adwithdrd(num)
# B.add(num) # 1如果有线程操作这个函数,也会执行add方法,会影响到最后的数据,最好的解决方法是在类中添加一个锁
def trans(A, B, num):
r = threading.RLock()
r.acquire()
A.adwithdrd(num)
B.add(num)
r.release()
t1 = threading.Thread(target=trans, args=(a1, b1, 100))
t3 = threading.Thread(target=trans, args=(a1, b1, 100))
t2 = threading.Thread(target=trans, args=(b1, a1, 200)) t1.start()
t2.start()
t3.start()
a1.__str__()
b1.__str__()

信号量:

信号量用来控制线程并发数的,BoundedSemaphore或Semaphore管理一个内置的计数 器,每当调用acquire()时-1,调用release()时+1。

计数器不能小于0,当计数器为 0时,acquire()将阻塞线程至同步锁定状态,直到其他线程调用release()。(类似于停车位的概念)

BoundedSemaphore与Semaphore的唯一区别在于前者将在调用release()时检查计数 器的值是否超过了计数器的初始值,如果超过了将抛出一个异常

应用:数据库连接池

import threading,time
class myThread(threading.Thread):
def run(self):
if semaphore.acquire():
print(self.name)
time.sleep(5)
semaphore.release()
if __name__=="__main__":
semaphore=threading.Semaphore(5)
thrs=[]
for i in range(100):
thrs.append(myThread())
for t in thrs:
t.start()

线程池

【更多参考】 http://www.cnblogs.com/wupeiqi/articles/6229292.html

条件变量同步1223

有一类线程需要满足条件之后才能够继续执行,Python提供了threading.Condition 对象用于条件变量线程的支持,它除了能提供RLock()或Lock()的方法外,还提供了 wait()、notify()、notifyAll()方法。

lock_con=threading.Condition([Lock/Rlock]): 锁是可选选项,不传入锁,对象自动创建一个RLock()。

应用:用于线程之间的信息交流

wait():条件不满足时调用,线程会释放锁并进入等待阻塞;

notify():条件创造后调用,通知等待池激活一个线程;

notifyAll():条件创造后调用,通知等待池激活所有线程

import threading,time
from random import randint
class Producer(threading.Thread):
def run(self):
global L
while True:
val=randint(0,100)
print('生产者',self.name,":Append"+str(val),L)
if lock_con.acquire():
L.append(val)
lock_con.notify() # notify并没有释放锁的能力,所以需要手动释放
lock_con.release() # 手动释放锁
time.sleep(3)
class Consumer(threading.Thread):
def run(self):
global L
while True:
lock_con.acquire() # 重新获得锁
if len(L)==0:
lock_con.wait() # wait进入等待并且释放锁
print('消费者',self.name,":Delete"+str(L[0]),L)
del L[0]
lock_con.release()
time.sleep(0.25) if __name__=="__main__": L=[]
lock_con=threading.Condition()
threads=[]
for i in range(5):
threads.append(Producer())
threads.append(Consumer())
for t in threads:
t.start()
for t in threads:
t.join()

Python学习---线程锁/信号量/条件变量同步/线程池1221的更多相关文章

  1. 线程私有数据TSD——一键多值技术,线程同步中的互斥锁和条件变量

    一:线程私有数据: 线程是轻量级进程,进程在fork()之后,子进程不继承父进程的锁和警告,别的基本上都会继承,而vfork()与fork()不同的地方在于vfork()之后的进程会共享父进程的地址空 ...

  2. Linux互斥锁、条件变量和信号量

    Linux互斥锁.条件变量和信号量  来自http://kongweile.iteye.com/blog/1155490 http://www.cnblogs.com/qingxia/archive/ ...

  3. Linux 线程同步的三种方法(互斥锁、条件变量、信号量)

    互斥锁 #include <cstdio> #include <cstdlib> #include <unistd.h> #include <pthread. ...

  4. linux c 线程间同步(通信)的几种方法--互斥锁,条件变量,信号量,读写锁

    Linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量.信号量和读写锁. 下面是思维导图:  一.互斥锁(mutex)  锁机制是同一时刻只允许一个线程执行一个关键部分的代码. 1 . ...

  5. APUE学习笔记——11 线程同步、互斥锁、自旋锁、条件变量

    线程同步     同属于一个进程的不同线程是共享内存的,因而在执行过程中需要考虑数据的一致性.     假设:进程有一变量i=0,线程A执行i++,线程B执行i++,那么最终i的取值是多少呢?似乎一定 ...

  6. 进程间通信机制(管道、信号、共享内存/信号量/消息队列)、线程间通信机制(互斥锁、条件变量、posix匿名信号量)

    注:本分类下文章大多整理自<深入分析linux内核源代码>一书,另有参考其他一些资料如<linux内核完全剖析>.<linux c 编程一站式学习>等,只是为了更好 ...

  7. linux 线程的同步 二 (互斥锁和条件变量)

    互斥锁和条件变量 为了允许在线程或进程之间共享数据,同步时必须的,互斥锁和条件变量是同步的基本组成部分. 1.互斥锁 互斥锁是用来保护临界区资源,实际上保护的是临界区中被操纵的数据,互斥锁通常用于保护 ...

  8. python 线程/线程锁/信号量

    单线程 #常规写法 import threading import time def sayhi(num): # 定义每个线程要运行的函数 print("running on number: ...

  9. C++11 中的线程、锁和条件变量

    转自:http://blog.jobbole.com/44409/ 线程 类std::thread代表一个可执行线程,使用时必须包含头文件<thread>.std::thread可以和普通 ...

随机推荐

  1. 【温故知新】C#基于事件的异步模式(EAP)

    在开发winform和调用asp.net的web service引用的时候,会出现许多命名为 MethodNameAsync 的方法. 例如: winform的按钮点击 this.button1.Cl ...

  2. Oracle Net Configuration(监听程序和网络服务配置)

    1.在Oracle服务端和客户端都安装完之后,就需要配置监听程序和本地网络服务,以便外部程序和工具的访问,所以Oracle提供了两款自带的工具来配置它们分别是 Net Configuration.Ne ...

  3. Kafka 0.9 新特性

    Kafka发布0.9了,这一重磅消息,让小伙伴们激动不已,来看看这个版本有哪些值得关注的地方吧! 一.安全特性 在0.9之前,Kafka安全方面的考虑几乎为0,在进行外网传输时,只好通过Linux的防 ...

  4. Node.js Express4.x生成程序骨架

    express 4.x版本中将命令工具分出来了,需要再安装一个命令工具,执行命令“npm install -g express-generator”完成后再测试就可以了. 最后通过"expr ...

  5. 如何使标签a处于不可用状态

    今天做项目的时候突然发现a标签下用disabled无法使它的点击事件失效(貌似ie下可以,没有测试过), 首先说一下项目要求,点击a标签(点击之后以防多次快速点击,这里需要点击后使标签a实现),触发a ...

  6. whatwg-fetch

    fetch 是什么 XMLHttpRequest的最新替代技术 fetch优点 接口更简单.简洁,更加语义化 基于promise,更加好的流程化控制,可以不断then把参数传递,外加 async/aw ...

  7. 判断当前IE浏览器是否支持JS

    1.server 2008 r2 64位中自带的IE默认不支持js,这样一些有JS的页面就是失效,所以如果要考虑这方面的系统,需要判断浏览器是否支持JS <div class="js- ...

  8. Expression Blend实例中文教程(12) - 样式和模板快速入门Style,Template

    在上一篇,介绍了Visual State Manager视觉状态管理器,其中涉及到控件的样式(Style)和模板(Template),本篇将详细介绍样式(Style)和模板(Template)在Sil ...

  9. node.js搭建https服务器

    HTTPS简介 HTTPS:(全称:Hypertext Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版. ...

  10. Java温故而知新(3)异常处理机制

    异常处理是程序设计中一个非常重要的方面,也是程序设计的一大难点,从C开始,你也许已经知道如何用if...else...来控制异常了,也许是自发的,然而这种控制异常痛苦,同一个异常或者错误如果多个地方出 ...