Python:进程挂起与futex(0x2a5fcc0,FUTEX_WAIT_PRIVATE,0,多线程中的NULL)

时间:2015-10-07 07:37:36

标签: python multithreading queue futex

所以我有一个队列:

q = Queue.Queue()

我正在放一些物品。

items = ["First", "Second"]
for val in items:
    q.put(val)

我正在产生15个线程。

for i in range(15):
   tname = 't-%s' % i
   t = my_thread(some_func, q, tname)
   t.start()

q.join()

my_thread类看起来如下:

class my_thread(threading.Thread):
    def __init__(self, some_func, q_, name=''):
       threading.Thread.__init__(self)
       self.func = some_func
       self.process_q = q_
       self.name = name
       self.prefix = name


    def run(self):
       stime = time.time()
       logging.info('%s thread staring at : %s' % (threading.currentThread().getname(), time.ctime(stime)))
       while True:
           if self.process_q.empty():
               break
           queue_item = self.process_q.get()
           self.name = self.prefix + '-' + queue_item
           try:
               #run the function
           except Exception as e:
               logging.error('Caught some error')
           finally:
               self.process_q.task_done()


       endTime = time.time()
       logging.info('%s thread finished at: %s' % (threading.currentThread().getName(), time.ctime(endTime)))

如果我查看日志,我看到的是两个或多个线程同时访问Queue,而当队列为空时,while循环不会中断。

假设t-0线程已从队列中取出"first"项。 但是t-2线程可能会在"second"线程可以接受它之前使用t-1项,从而使队列为空...但是当t-1执行self.process_q.empty()检查时,队列不是空的。所以t-1线程永远不会退出/结束,而是悬空。

如果我对进程ID进行了分析,我会得到以下内容:

Process 13307 attached
futex(0x2a5fcc0, FUTEX_WAIT_PRIVATE, 0, NULL

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:5)

你的线程随机挂在阻塞的self.process_q.get()函数中。 - >的竞争危害

目前,线程已启动,队列不为空。 代码部分......

...
if self.process_q.empty():
    break
queue_item = self.process_q.get()
...

未在所有线程上同步。因此,可能有超过2个线程(队列大小= 2)通过if条件。两个线程从self.process_q.get()函数获取结果,而其他线程阻塞并等待队列中的结果。

在所有非守护程序线程完成之前,python程序无法退出。所以它永远挂起。

考虑以守护进程模式设置线程:

for i in range(15):
    tname = 't-%s' % i
    t = my_thread(some_func, q, tname)
    t.setDaemon(True)
    t.start()

来自https://docs.python.org/2/library/threading.html#threading.Thread.daemon

  

<强>守护程序

     

一个布尔值,指示此线程是否是守护程序线程   (真)与否(假)。这必须在调用start()之前设置,   否则引发RuntimeError。它的初始值是继承自的   创建线程;主线程不是守护程序线程   因此,在主线程中创建的所有线程都默认为daemon =   假

     

当没有活着的非守护程序线程时,整个Python程序退出。

通过将守护程序模式设置为 true ,程序在队列为空(q.join())后退出。

答案 1 :(得分:-1)

我遇到了同样的问题,并确定在RHEL7计算机上有一个“ python / usr / bin / goferd ”进程消耗了100%的CPU。

[root @ RHELLINUXPROD〜]#ps aux | grep -i 1268 根1268 90.4 0.0 1030428 25304 Ssl Jun 04 111901:11 python / usr / bin / goferd --foreground

问题识别: 此“ / usr / bin / goferd”过程将与客户端计算机上的RedHat卫星订阅相关。

这是RedHat卫星订阅代理“ katello-ca-consumer-latest.noarch.rpm”的错误

解决方案:

临时解决方案:

在您的RHEL7计算机上找到已安装的katello代理。

[root @ RHELLINUXPROD〜]#katello-ca-consumer-rhsat-i01.0-1.noarch katello-agent-1.5.3-7.el7sat.noarch

在客户端RHEL7计算机上清理并取消注册Redhat订阅

*#个订阅管理器干净

取消订阅管理器*

从RHEL7客户端中删除已安装的katello代理

[root @ RHELLINUXPROD〜]#rpm -e katello-ca-consumer-rhsat-i01.0-1.noarch [root @ RHELLINUXPROD〜]#rpm -e katello-agent-1.5.3-7.el7sat.noarch

现在您可以看到使用“ ps -ef | grep -i goferd”命令输出的python进程已停止并且服务器CPU利用率恢复正常。

再次重新安装katello aganet并将服务器订阅到redhat卫星。

永久解决方案:

您必须将卫星升级到最新版本,然后才能永久解决此问题。

感谢与问候 纳马西瓦姆