@@ -11,22 +11,51 @@ namespace Python.EmbeddingTest
1111{
1212 public class TestInterrupt
1313 {
14- private IntPtr _threadState ;
15-
14+ PyObject threading ;
1615 [ OneTimeSetUp ]
1716 public void SetUp ( )
1817 {
1918 PythonEngine . Initialize ( ) ;
20- _threadState = PythonEngine . BeginAllowThreads ( ) ;
19+ // workaround for assert tlock.locked() warning
20+ threading = Py . Import ( "threading" ) ;
2121 }
2222
2323 [ OneTimeTearDown ]
2424 public void Dispose ( )
2525 {
26- PythonEngine . EndAllowThreads ( _threadState ) ;
26+ threading . Dispose ( ) ;
2727 PythonEngine . Shutdown ( ) ;
2828 }
2929
30+ [ Test ]
31+ public void PythonThreadIDStable ( )
32+ {
33+ long pythonThreadID = 0 ;
34+ long pythonThreadID2 = 0 ;
35+ var asyncCall = Task . Factory . StartNew ( ( ) =>
36+ {
37+ using ( Py . GIL ( ) )
38+ {
39+ Interlocked . Exchange ( ref pythonThreadID , ( long ) PythonEngine . GetPythonThreadID ( ) ) ;
40+ Interlocked . Exchange ( ref pythonThreadID2 , ( long ) PythonEngine . GetPythonThreadID ( ) ) ;
41+ }
42+ } ) ;
43+
44+ var timeout = Stopwatch . StartNew ( ) ;
45+
46+ IntPtr threadState = PythonEngine . BeginAllowThreads ( ) ;
47+ while ( Interlocked . Read ( ref pythonThreadID ) == 0 || Interlocked . Read ( ref pythonThreadID2 ) == 0 )
48+ {
49+ Assert . Less ( timeout . Elapsed , TimeSpan . FromSeconds ( 5 ) , "thread IDs were not assigned in time" ) ;
50+ }
51+ PythonEngine . EndAllowThreads ( threadState ) ;
52+
53+ Assert . IsTrue ( asyncCall . Wait ( TimeSpan . FromSeconds ( 5 ) ) , "Async thread has not finished in time" ) ;
54+
55+ Assert . AreEqual ( pythonThreadID , pythonThreadID2 ) ;
56+ Assert . NotZero ( pythonThreadID ) ;
57+ }
58+
3059 [ Test ]
3160 public void InterruptTest ( )
3261 {
@@ -39,26 +68,31 @@ public void InterruptTest()
3968 return PythonEngine . RunSimpleString ( @"
4069import time
4170
42- while True:
43- time.sleep(0.2)" ) ;
71+ try:
72+ while True:
73+ time.sleep(0.2)
74+ except KeyboardInterrupt:
75+ pass" ) ;
4476 }
4577 } ) ;
4678
4779 var timeout = Stopwatch . StartNew ( ) ;
80+
81+ IntPtr threadState = PythonEngine . BeginAllowThreads ( ) ;
4882 while ( Interlocked . Read ( ref pythonThreadID ) == 0 )
4983 {
5084 Assert . Less ( timeout . Elapsed , TimeSpan . FromSeconds ( 5 ) , "thread ID was not assigned in time" ) ;
5185 }
86+ PythonEngine . EndAllowThreads ( threadState ) ;
5287
53- using ( Py . GIL ( ) )
54- {
55- int interruptReturnValue = PythonEngine . Interrupt ( ( ulong ) Interlocked . Read ( ref pythonThreadID ) ) ;
56- Assert . AreEqual ( 1 , interruptReturnValue ) ;
57- }
88+ int interruptReturnValue = PythonEngine . Interrupt ( ( ulong ) Interlocked . Read ( ref pythonThreadID ) ) ;
89+ Assert . AreEqual ( 1 , interruptReturnValue ) ;
5890
91+ threadState = PythonEngine . BeginAllowThreads ( ) ;
5992 Assert . IsTrue ( asyncCall . Wait ( TimeSpan . FromSeconds ( 5 ) ) , "Async thread was not interrupted in time" ) ;
93+ PythonEngine . EndAllowThreads ( threadState ) ;
6094
61- Assert . AreEqual ( - 1 , asyncCall . Result ) ;
95+ Assert . AreEqual ( 0 , asyncCall . Result ) ;
6296 }
6397 }
6498}
0 commit comments