两个线程之间的模糊锁定似乎与全局解释器锁定或其他一些“幕后锁定”有关,我不知道如何继续故障排除。任何如何消除锁定的提示将不胜感激。
该问题在更大的代码集中重现(不规则且有些随机)。代码是严格的python。Python 版本是 2.6.5(在 Linux 上)。当锁定发生以下情况时,数小时的故障排除已减少问题:
- 该程序只有两个正在运行的线程
- 线程同时调用由单个 threading.RLock 保护的方法
- 线程 1 通过 acquire() 获得了锁 [加上其他一些锁]
- 线程 2 调用了 acquire() 并确认正在等待锁
- 线程 1 能够使用 print() 向控制台打印,但是它被一个简单的非阻塞库调用锁定
#5 中的攻击性调用是函数 unicode.encode,它应该是非阻塞的。线程 1 中线程锁定位置的以下代码将(如预期)打印“A”和“B”:
print('A')
print('B')
但是,以下只会打印“A”并阻塞线程:
print('A')
u'hello'.encode('utf8') # This dummy (non-blocking) call locks up Thread 1
print('B')
这对我来说毫无意义。两个线程之间不存在逻辑死锁条件。线程 1 被非阻塞库调用阻塞,该调用不会以任何方式干扰线程 2,线程 2 只是静静地等待获取 RLock。我能想到的线程 1 被阻塞的唯一原因是它正在等待 GIL。
任何想法如何进一步解决这个问题,或者任何机制以某种方式控制或操纵 GIL 操作作为解决方法?
编辑:针对样本偏差的一些附加信息(感谢您的回复)。我在追踪时遇到了问题,因为这个问题似乎对任何可能干扰两个线程之间时间的事情都非常敏感。但是,仅使用 -f 选项运行 strace ,经过几次迭代后,我能够获得跟踪。
线程 1 包含这三个调试语句,它们应将两行“CHECK_IN”和“CHECK_TEST”打印到控制台:
print('CHECK IN')#DEBUG
u'hello'.encode('utf8')
print('CHECK TEST')#DEBUG
这是 strace 的最后一页:
8605 mmap2(NULL, 266240, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb753d000
8605 mmap2(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0xb6d3c000
8605 mprotect(0xb6d3c000, 4096, PROT_NONE) = 0
8605 clone(child_stack=0xb753c494, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb753cbd8, {entry_number:6, base_addr:0xb753cb70, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb753cbd8) = 8606
8606 set_robust_list(0xb753cbe0, 0xc <unfinished ...>
8605 futex(0xa239138, FUTEX_WAIT_PRIVATE, 0, NULL <unfinished ...>
8606 <... set_robust_list resumed> ) = 0
8606 futex(0xa239138, FUTEX_WAKE_PRIVATE, 1) = 1
8605 <... futex resumed> ) = 0
8606 gettimeofday( <unfinished ...>
8605 futex(0xa272398, FUTEX_WAIT_PRIVATE, 0, NULL <unfinished ...>
8606 <... gettimeofday resumed> {1301528807, 326496}, NULL) = 0
8606 futex(0xa272398, FUTEX_WAKE_PRIVATE, 1) = 1
8605 <... futex resumed> ) = 0
8606 futex(0xa272398, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
8605 gettimeofday( <unfinished ...>
8606 <... futex resumed> ) = 0
8605 <... gettimeofday resumed> {1301528807, 326821}, NULL) = 0
8606 futex(0xa272398, FUTEX_WAIT_PRIVATE, 0, NULL <unfinished ...>
8605 futex(0xa272398, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
8606 <... futex resumed> ) = -1 EAGAIN (Resource temporarily unavailable)
8605 <... futex resumed> ) = 0
8606 gettimeofday( <unfinished ...>
8605 futex(0xa272398, FUTEX_WAIT_PRIVATE, 0, NULL <unfinished ...>
8606 <... gettimeofday resumed> {1301528807, 326908}, NULL) = 0
8606 futex(0xa272398, FUTEX_WAKE_PRIVATE, 1) = 1
8605 <... futex resumed> ) = 0
8606 futex(0xa272398, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
8605 futex(0xa1b0d70, FUTEX_WAIT_PRIVATE, 0, NULL <unfinished ...>
8606 <... futex resumed> ) = 0
8606 stat64("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
8606 fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
8606 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6d3b000
8606 write(1, "CHECK IN\n", 9) = 9
8606 futex(0xa115270, FUTEX_WAIT_PRIVATE, 0, NULL
在程序锁定之前,三行代码的输出如下:
CHECK IN
因此 strace 显示了线程 1 (#8606) 如何写入 'CHECK_IN' 字符串,并在到达 unicode.encode 调用时进入永远不会返回的等待状态。
顺便说一句,我将在所有模块中进行一些未来的导入,以符合一些较新的 python 约定......
from __future__ import print_function, unicode_literals
...但我看不出它们应该有什么不同——尤其是当 u'hello' 字符串被显式调用为 unicode 字符串时。