线程锁

问题现象: 多线程情况下,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. 获取app应用的包名

    1.获取哪个app包名,就打开哪个app 2.在dos窗口下输入: adb shell "dumpsys window | grep mCurrentFocus" 获取包名

  2. CentOS7 wget 安装Redis,开机启动配置

      安装 GCC yum install gcc yum install tcl 安装wget yum install wget 1. 下载Redis wget http://download.red ...

  3. selenium+python(数据驱动测试)

    自动化领域的两种驱动,对象驱动与数据驱动 数据驱动:测试数据的改变引起执行结果的改变 叫 数据驱动 关键字驱动:测试对象名字的改变起引起测试结果的改变 叫 关键字驱动 1 .读取文件参数化   以百度 ...

  4. Django多进程日志文件问题

    Django多进程日志文件问题 最近使用Django做一个项目.在部署的时候发现日志文件不能滚动(我使用的是RotatingFileHandler),只有一个日志文件. 查看Log发现一个错误消息:P ...

  5. ubuntu16上安装openJDK.md

    ubuntu16上安装openJDK.md 环境 操作系统:ubuntu 16.04.2 LTS 安装 当你不需要安装oracle的JDK时,使用openJDK,安装就比较方便. sudo apt-g ...

  6. SpringMVC的数据回现

    一.什么是数据回显 数据提交后,如果出现错误,将刚才提交的数据回显到刚才的提交页面. 二.pojo数据回显方法 1.springmvc默认对pojo数据进行回显. pojo数据传入controller ...

  7. js&&jQuery实现省市区三级联动

    代码参考了:https://codepen.io/anon/pen/WzyNQB;根据自己的需要修改了一下,挂个出处 1.前端页面代码 <html> <head> <me ...

  8. WES7 定制界面完整过程(去除所有windows标识)

    转载但有改动 红色字体记录 目的:实验从启动开始到出现桌面,不出现任何windows图标或标识.重大提示:在某些虚拟机上面操作和真实机器是不一样的,主机会容易很多;所以在虚拟机无法实现效果的时候使用主 ...

  9. CMS gc随记

    在查看CMS相关中文资料时,都提到了 并发预清理(Concurrent precleaning) 重新标记(STW remark) 目的是重新标记在并发标记阶段,由于对象状态的改变而标记遗漏的对象. ...

  10. 利用canvas制作图片(可缩放和平移)+相框+文字

    前言: 公司一个售前问我能不能用H5做一个手机拍照,给相片添加相框和添加文字上传到服务器的功能,我当时一琢磨觉得可行,就利用空余时间做了一个demo,去掉了拍照和上传,如果以后有机会,会给补上,当然对 ...