python中的线程锁无法按需工作 [英] Threading lock in python not working as desired

查看:121
本文介绍了python中的线程锁无法按需工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试保护线程中的数据免受主线程的侵害.我有以下代码:

I am trying to protect data inside my thread from the main thread. I have the following code:

lock = threading.Lock()

def createstuff(data):
    t= threading.Thread(target=func, args=(data,))
    t.start()

def func(val):
    with lock:
        print 'acquired'
        time.sleep(2)
        print ('Value: %s, : %s'%(val, threading.currentThread().getName()))
        print 'released\n'

ags_list = ['x']

createstuff(ags_list)

rn =random.randint(5,50)
print 'random no:', rn
ags_list[0] = rn 

它产生输出:

acquired
random no: 10
Value: [10], : Thread-1
released

为什么更改主线程中的列表会导致另一个线程中的列表发生变化,即使该列表已被锁定也是如此?我该怎么做才能防止这种情况发生?谢谢.

Why does changing the list in main thread cause the list inside another thread to mutate even though it is locked? What can I do to prevent it? Thanks.

推荐答案

因为仅当您在使列表发生变化的任何地方使用锁时,锁才会起作用,因此,仅当您调用该锁时,它并不是在所有地方都起作用的魔术咒语一个地方.

because the lock only works out if you're using everywhere you're mutating the list, it's not a magic spell that works everywhere if you call it at only one place.

要保护列表,您需要在两个线程上添加锁上下文:

To protect the list you need to add the lock context on both threads:

lock = threading.Lock()

def createstuff(data):
    t= threading.Thread(target=func, args=(data,))
    t.start()

def func(val):
    with lock:
        print 'thread: acquired'
        time.sleep(2)
        print ('Value: %s, : %s'%(val, threading.currentThread().getName()))
        print 'thread released'

ags_list = ['x']


createstuff(ags_list)

with lock:
    print 'thread: acquired'
    rn =random.randint(5,50)
    print 'random no:', rn
    ags_list[0] = rn 
    print 'thread: released'

您可以创建一个线程安全列表,例如:

You could create a thread safe list such as:

class ThreadSafeList(list):
    def __init__(self, *args):
        super(ThreadSafeList, self).__init__(*args)
        self.lock = threading.Lock()
    def __setitem__(self, idx, value):
        with self.lock:
            print 'list acquired'
            super(ThreadSafeList, self)[idx] = value
            print 'list released'

然后使用它:

def createstuff(data):
    t= threading.Thread(target=func, args=(data,))
    t.start()

def func(val):
    time.sleep(2)
    print ('Value: %s, : %s'%(val, threading.currentThread().getName()))

args_list = ThreadSafeList(['x'])
createstuff(args_list)
rn =random.randint(5,50)
print 'random no:', rn
args_list[0] = rn 

当然,这只是一个需要完成和改进的示例.在这里,我宁愿专注于这一点.

of course that's only an example that needs to be completed and improved. Here I preferred to focus on the point.

尽管您不需要在线程中进行锁定,因为从列表访问值是(自动)原子只读操作,因此仅在在内部访问值之前或之后才发生列表的更改.列表,而不是因为它正在访问值.因此,最后您的示例中不应出现任何种族问题.

Though you do not need a lock in the thread, because accessing a value from a list is (afaict) an atomic read only action, so the mutation of the list can only happen before or after the value is being accessed within the list, not as it is accessing the value. So in the end you should not have any race issue in your example.

如果您要修改列表的值,或对数据进行非原子访问,则锁定可能很有用.

If you were modifying the list's value, or doing a non atomic access to data, then the lock could be useful.

N.B .:如果您认为它可以通过其他方式工作:互斥机制(通过Lock实现)不保护数据,而是保护两个执行线程无法同时执行.如果在线程A 中声明锁,则在线程B 中声明相同锁之前,线程B 将等待线程A 取消激活该锁,直到完成它的工作为止.

N.B.: in case you thought it could work any other way: the mutex mechanism (implemented through Lock) does not protect data, it protects two threads of execution from executing at the same time. If you assert a lock in Thread A, before asserting the same lock in Thread B, Thread B will wait for Thread A to deassert the lock until doing its job.

这篇关于python中的线程锁无法按需工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆