前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >线程的锁机制

线程的锁机制

作者头像
养码场
发布2019-06-18 17:43:42
1.4K0
发布2019-06-18 17:43:42
举报
文章被收录于专栏:养码场养码场养码场

本篇文章分享的是多线程的锁机制。

多线程编程访问共享变量时会出现问题,但是多进程编程访问共享变量不会出现问题。因为多进程中,同一个变量各自有一份拷贝存在于每个进程中,互不影响,而多线程中,所有变量都由所有线程共享。

多个进程之间对内存中的变量不会产生冲突,一个进程由多个线程组成,多线程对内存中的变量进行共享时会产生影响,所以就产生了死锁问题,怎么解决死锁问题是本节主要介绍的内容。

1、变量的作用域

一般在函数体外定义的变量称为全局变量,在函数内部定义的变量称为局部变量。全局变量所有作用域都可读,局部变量只能在本函数可读。函数在读取变量时,优先读取函数本身自有的局部变量,再去读全局变量。

内容如下:

运行脚本得到以下结果。

如果注释掉change()函数里的 global v1,那么得到的返回值是。

在本例中在change()函数外定义的变量balance是全局变量,在change()函数内定义的变量num是局部变量,全局变量默认是可读的,可以在任何函数中使用,如果需要改变全局变量的值,需要在函数内部使用global定义全局变量,本例中在change()函数内部使用global定义全局变量balance,在函数里就可以改变全局变量了。

在函数里可以使用全局变量,但是在函数里不能改变全局变量。想实现多个线程共享变量,需要使用全局变量。在方法里加上全局关键字 global定义全局变量,多线程才可以修改全局变量来共享变量。

2、多线程中的锁

多线程同时修改全局变量时会出现数据安全问题,线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。在本例中我们生成2个线程同时修改change()函数里的全局变量balance时,会出现数据不一致问题。

本案例文件名为PythonFullStackChapter03 hreadDemo03.py,内容如下。

运行以上脚本,当2个线程运行次数达到500000次时,会出现以下结果。

在本例中定义了一个全局变量balance,初始值为100,当启动2个线程后,先加后减,理论上balance应该为100。线程的调度是由操作系统决定的,当线程t1和t2交替执行时,只要循环次数足够多,balance结果就不一定是100了。从结果可以看出,在本例中线程t1和t2同时修改全局变量balance时,会出现数据不一致问题。

值得注意

在多线程情况下,所有的全局变量有所有线程共享。所以,任何一个变量都可以被任何一个线程修改,因此,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了。

在多线程情况下,使用全局变量并不会共享数据,会出现线程安全问题。线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。

不会出现数据不一致,在单线程运行时没有代码安全问题。写多线程程序时,生成一个线程并不代表多线程。在多线程情况下,才会出现安全问题。

针对线程安全问题,需要使用”互斥锁”,就像数据库里操纵数据一样,也需要使用锁机制。某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

互斥锁的核心代码如下:

如果要确保balance计算正确,使用threading.Lock()来创建锁对象lock,把 lock.acquire()和lock.release()加在同步代码块里,本例的同步代码块就是对全局变量balance进行先加后减操作。

当某个线程执行change()函数时,通过lock.acquire()获取锁,那么其他线程就不能执行同步代码块了,只能等待知道锁被释放了,获得锁才能执行同步代码块。由于锁只有一个,无论多少线程,同一个时刻最多只有一个线程持有该锁,所以修改全局变量balance不会产生冲突。改良后的代码内容如下。

在例子中2个线程同时运行lock.acquire()时,只有一个线程能成功的获取锁,然后执行代码,其他线程就继续等待直到获得锁位置。获得锁的线程用完后一定要释放锁,否则其他线程就会一直等待下去,成为死线程。

在运行上面脚本就不会产生输出信息,证明代码是安全的。把 lock.acquire()和lock.release()加在同步代码块里,还要注意锁的力度不要加的太大了。第一个线程只有运行完了,第二个线程才能运行,所以锁要在需要同步代码里加上。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-06-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 养码场 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档