【问题标题】:Python Threading: Making the thread function return from an external signalPython Threading:使线程函数从外部信号返回
【发布时间】:2017-02-16 17:00:15
【问题描述】:

谁能指出这段代码有什么问题。我试图通过一个变量标志返回线程,我想在我的主线程中控制它。

test27.py

import threading
import time

lock = threading.Lock()

def Read(x,y):
    flag = 1
    while True:
        lock.acquire()
        try:
            z = x+y; w = x-y
            print z*w
            time.sleep(1)
            if flag == 0:
                print "ABORTING"
                return
        finally:
            print " SINGLE run of thread executed"
            lock.release()

test28.py

import time, threading

from test27 import Read

print "Hello Welcome"
a = 2; b = 5
t = threading.Thread(target = Read, name = 'Example Thread', args = (a,b))
t.start()
time.sleep(5)
t.flag = 0 # This is not updating the flag variable in Read FUNCTION
t.join() # Because of the above command I am unable to wait until the thread finishes. It is blocking.
print "PROGRAM ENDED"

【问题讨论】:

    标签: python multithreading time


    【解决方案1】:

    不应在线程中跟踪常规变量。这样做是为了防止竞争条件。您必须使用线程安全构造在线程之间进行通信。对于一个简单的标志使用threading.Event。您也不能通过线程对象访问局部变量flag。它是本地的,并且仅在范围内可见。您必须使用全局变量,如下面的示例所示,或者在调用线程并使用成员变量之前创建一个对象。

    from threading import Event
    flag = Event()
    
    def Read(x,y):
        global flag
        flag.clear()
        ...
        if flag.is_set():
            return
    

    主线程:

    sleep(5)
    flag.set()
    

    P.S.:我刚刚注意到您尝试在线程中使用 lock(),但未能在主线程中使用它。对于一个简单的标志去事件。对于 lock(),您需要锁定这两个部分并降低死锁的风险。

    【讨论】:

    • 我无法理解您的回答。我试过阅读它,请你用初学者的术语解释一下。我编辑了我的问题,就像我是如何做的以及我想要的那样,代码偶尔会起作用。我没有将全局变量定义为标志。
    • 初级版:1.在Read之外无法访问flag。 2、你错误地使用了lock;应该改用事件。只需复制此示例:itsjustsosimple.blogspot.com/2014/01/…
    • 我将标志定义为您提到的全局,但仍然无法访问它。 flag.set() 给我一个错误
    • NameError: name 'flag' is not defined -- 发生在我的 test28.py 中的 flag.set() 处。关于锁。我是否在更新的代码中正确使用它。
    • 标志错误可能是因为您将代码拆分为两个文件。您现在需要从 test27 导入标志。我只是在猜测,因为您没有向我展示新代码。至于锁:你没有在test28中锁定对标志的访问,所以你没有正确使用它。
    【解决方案2】:

    Thread 类可以使用target 参数进行实例化。然后你只需给它一个应该在新线程中执行的函数。这是一种启动简单线程的便捷方式,但为了获得更多控制权,通常更容易从Thread 继承一个类,该类具有额外的成员变量,例如用于中止的flag

    例如:

    import time
    import threading
    
    class MyThread(threading.Thread):
        def __init__(self, x, y):
            super().__init__()
            # or in Python 2:
            # super(MyThread, self).__init__()
            self.x = x
            self.y = y
            self._stop_requested = False
    
        def run(self):
            while not self._stop_requested:
                z = self.x + self.y
                w = self.x - self.y
                print (z * w)
                time.sleep(1)
    
        def stop(self, timeout=None):
            self._stop_requested = True
            self.join(timeout)
    

    然后,要启动线程,调用start(),然后停止它调用stop()

    >>> def run_thread_for_5_seconds():
    ...     t = MyThread(3, 4)
    ...     t.start()
    ...     time.sleep(5)
    ...     t.stop()
    ...
    >>> run_thread_for_5_seconds()
    -7
    -7
    -7
    -7
    -7
    >>>
    

    【讨论】:

    • 虽然这适用于一个简单的示例,但在实际应用程序中使用不安全的线程消息传递会影响您的体验。 "If you want your threads to stop gracefully, make them non-daemonic and use a suitable signalling mechanism such as an Event." - docs.python.org/3/library/threading.html
    • 为了进一步阅读,我建议查找一个称为“竞争条件”的问题
    • @Muposat 这个线程是非守护进程,因为daemon defaults to False。赋值 self._stop_requested = True 是线程安全的。属性_stop_requested 仅从主线程写入,在线程启动前恰好一次,在线程运行时恰好一次。如果您在此处看到竞态条件,请解释它是如何发生的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-23
    • 2016-08-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多