线程锁

问题现象: 多线程情况下,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. JWT(Json Web Token)初探与实践

    前言什么是JWT?为什么使用JWT?什么时候使用JWT?JWT的基本结构HeaderPayloadSignature将他们放在一起项目实践JWT后端前端关于安全性总结参考 协议标准:https://t ...

  2. Win7/Vista/Server2008下VS 环境 调试调用 HTTP.SYS 无法启动监听服务及启动后其他机器无法访问端口

    一. VS调试在Win7(vista系列)操作系统下 HttpListener无法绑定多个 指定IP.端口问题 来自:http://www.cnblogs.com/ryhan/p/4195693.ht ...

  3. unittest简介

    unittest是python里面的单元测试框架 1 unittest 简介 1).先导入 unittest2).用 help 函数查看源码解析3).查看描述:Python unit testing ...

  4. [转载]java.ByteArrayInputStream与ByteArrayOutputStream再次理解

    一次看到ByteArrayOutputStream的时候是在Nutch的部分源码,后来在涉及IO操作时频频发现这两个类的踪迹,觉得确实是很好用,所以把它们的用法总结一下. ByteArrayOutpu ...

  5. Jedis连接redis

    今天与大家分享下,Jedis连接池使用.先看一段JAVA 代码:         JedisPoolConfig config = new JedisPoolConfig();         con ...

  6. 使用webgl(three.js)创建3D机房(升级版)-普通机房

    序: 目前市面上的数据中心主要分两大类,一类属于普通数据中心,机柜按照XY轴 有序排放,一类属于微模块集合的数据中心,多个机柜组合而成的微模块.  本节课主要详细讲解普通数据中心的可视化展示,浏览器直 ...

  7. bzoj 4161: Shlw loves matrixI

    Description 给定数列 {hn}前k项,其后每一项满足 hn = a1h(n-1) + a2h(n-2) + ... + ak*h(n-k) 其中 a1,a2...ak 为给定数列.请计算 ...

  8. 公司管理系列--Facebook 如何化茧成蝶[转]

    拒绝传统,看 Facebook 如何以三大法宝化茧成蝶:人才吸引.工程师文化和项目开发流程   我将结合之前在Facebook的四年工作经验,介绍Facebook创新的管理方法以及整个工程文化形成的方 ...

  9. spring-boot配置热更新

    spring boot使用的时候会遇到不断重启启动类的情况,热更新可以免去手动重启的烦恼,spring boot应用配置热更新主要有两种方式: 1.使用springloaded 配置pom.xml文件 ...

  10. [android] 练习viewpagerindicator的使用(一)

    主要是学习一下使用这个库 activity_main.xml <?xml version="1.0" encoding="utf-8"?> < ...