java - 如何理解自旋锁和互斥锁?
给我你的怀抱
给我你的怀抱 2017-06-14 10:51:20
0
3
780

网上的文章看了很多还是很迷茫,谁能通俗易懂的给我解释一下这两个概念啊?

我在python多线程编码中一般都是在线程的run方法中用while True死循环,然后在死循环的循环体末尾调用queue.task_done移除该队列,然后在主线程调用queue的join方法阻塞主线程,防止主线程直接结束,请问我这种多线程编码方式是否合理?会不会有什么bug?另外请问一下我在run中调用死循环是不是就叫做自旋锁?

给我你的怀抱
给我你的怀抱

全部回复(3)
小葫芦

首先要了解什么是互斥锁,互斥锁代表的意思是什么,
就是在两个线程A,B 访问同一块内存的时侯。
理想情况下我们的执行顺序应该是 A 完全执行完后,B来执行
但是,执行是有占用CPU指令时间的,如果不用任何机制的话,当A执行到一半时,B占用了CPU,B去处理这段内存,然后B执行完毕,A再得到CPU,内存数据不就出错了吗?
为了内存的数据安全。就采用了一种互斥的技术,A访问这段内存的时候,首先判断这段内存有没有在使用中的标志(取个名字叫做锁),没有的话对这段内存加一个标志(锁),然后A在处理这段内存,A处理完了解锁。如果在A处理内存这个时候B来访问的话,B看到这段内存有使用中的标志(锁)了,B可以有好几种行为。行为一:占用CPU。不断循环并测试锁的状态,线程不会挂起(睡眠),处于忙等状态,采用这种行为的锁叫做自旋锁。行为二:线程B休眠阻塞,放弃CPU,直到A执行完了,锁没了,再使用内存。这种行为叫做互斥锁。看到这里你大概也明白了,锁就是实现互斥作用的同步机制。自旋锁就是互斥锁的一种情况(等待的时候会占用CPU的互斥锁)罢了。
不要被名称所误导。要了解背后的机制,换个名字也要明白,
参考链接 链接描述

过去多啦不再A梦

1.Python多线程run方法的中使用while循环时,如果在循环体没有使用停止程序机制,会一直运行下去.因此楼主如果想让编码方式得当,可以使用信号量或者其他变量机制通知循环体停止,或者判断队列是否为空,若为空,直接break,退出循环.

2.run中的死循环不是自旋锁,假如循环体内有资源竞争,给加了个锁,但这种锁也是互斥锁.
python的锁使用的是信号量semaphore,不是spinlock.

// https://svn.python.org/projects/python/trunk/Python/thread_atheos.h
static int fastmutex_lock(fastmutex_t * mutex)
{
    atomic_t prev = atomic_add(&mutex->count, 1);
    if (prev > 0)
        return lock_semaphore(mutex->sem);
    return 0;
}

自旋锁:多线程同时访问同一个资源,为防止资源的读取修改不一致设置的一种锁,如果线程访问资源时,已经有线程占有资源,那么后者线程会等待当前线程释放资源,此时后者(不休眠)一直运行CPU检测前者占有资源是否释放,这种后者访问并一直检测资源占有的机制就是自旋锁.

互斥锁:目的和自旋锁一样,但机制不一样,当线程占用资源后,加上锁,后者线程访问时,由于资源被占有,转入休眠(sleep)状态,等资源被释放后,通过信号量通知排队等候的线程。

过去多啦不再A梦

Python代码会按照这样的流程进行运行,

  1. 设置GIL

  2. 切换到某一个线程

  3. 运行

  4. 线程退出,设置为休眠状态

  5. 解锁GIL

  6. 重复以上操作

可能是因为GIL的原因,我似乎没有在Python里面看到过自旋锁,更多使用的是互斥锁。

下面是我以前写多线程的方法,仅供参考~

import Queue
from threading import Thread

temp_queue = Queue.Queue()


class Test(Thread):
    def __init__(self):
        Thread.__init__(self)

    def run(self):
        while temp_queue.empty() is False:
            pass
            # do sth here
            # temp = temp_queue.get()


tasks = []
for i in range(10):
    tasks.append(Test())

for task in tasks:
    task.start()

for task in tasks:
    task.join()

既然是队列,Queue中Queue().get()中说明了Remove and return an item from the queue.

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!