【问题标题】:What could possibly go wrong when not locking write operation here?如果不在这里锁定写操作,可能会出现什么问题?
【发布时间】:2013-11-25 07:53:13
【问题描述】:

假设一个类 WorkerThread 实现了一个字段 running,该字段指示线程在启动后是否应该继续工作。

class WorkerThread(threading.Thread):

    running = False

    def run(self):
        self.running = True
        while self.running:
            # .. do some important stuff
            pass

def main():
    t = WorkerThread()
    t.start()

    # .. do other important stuff

    t.running = False
    t.join()

从主线程修改t.running 时是否有可能出错,而不锁定该字段的读写操作?这是什么?

【问题讨论】:

  • 不是答案,但您可以尝试使用锁。让线程有一个threading.Lock 实例,让main 方法获取它。在run 方法中,使用while not self.lock.acquire(False):,完成后在main 中释放。获取的False 参数使其非阻塞,如果无法获取它,将立即返回False(因为main 尚未释放它)

标签: python multithreading thread-safety locking


【解决方案1】:

主线程和工作线程可以在不共享缓存的内核上运行。由于没有同步,对t.running 的写入可能永远从主线程的缓存共享到工作线程的缓存。

什么同步意味着不仅仅是“我想要独占访问”。这也意味着,“我想将我的写入分享给其他线程,并查看来自其他线程的写入”。没有同步意味着你不需要那些东西。不同步并不能阻止它们发生(并且在某些系统/架构上它们会比其他更频繁地发生),它只是无法保证它们会发生。

在实践中,您可能会发现,如果 CPython 定期采用 GIL,即使在与 Intel 不同,没有一致缓存的架构上,这些事情也会自行解决。

【讨论】:

    【解决方案2】:

    根据您的要求使用threading.Event() 对象而不是标志

    class WorkerThread(threading.Thread):
    
        def __init__(self):
            super(WorkerThread, self).__init__()
            self.running = threading.Event()
    
        def run(self):
            self.running.set()
            while self.running.is_set():
                # .. do some important stuff
                pass
        def halt(self):
            self.running.clear()
    
    def main():
        t = WorkerThread()
        t.start()
    
        # .. do other important stuff
    
        t.halt()
        t.join()
    

    检查是否正在运行t.is_alive()

    【讨论】:

      【解决方案3】:

      “运行”字段是共享状态,你需要用某种监视器来保护它。在没有同步访问这个共享状态的情况下,它的可见性语义很难推理,你会得到意想不到的结果。

      【讨论】:

        猜你喜欢
        • 2021-05-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-15
        • 2020-10-12
        • 2018-02-02
        • 2012-01-17
        • 2017-09-24
        相关资源
        最近更新 更多