diff --git a/src/embed_tests/TestInterrupt.cs b/src/embed_tests/TestInterrupt.cs
index a40407782..e344a8ccb 100644
--- a/src/embed_tests/TestInterrupt.cs
+++ b/src/embed_tests/TestInterrupt.cs
@@ -11,22 +11,51 @@ namespace Python.EmbeddingTest
{
public class TestInterrupt
{
- private IntPtr _threadState;
-
+ PyObject threading;
[OneTimeSetUp]
public void SetUp()
{
PythonEngine.Initialize();
- _threadState = PythonEngine.BeginAllowThreads();
+ // workaround for assert tlock.locked() warning
+ threading = Py.Import("threading");
}
[OneTimeTearDown]
public void Dispose()
{
- PythonEngine.EndAllowThreads(_threadState);
+ threading.Dispose();
PythonEngine.Shutdown();
}
+ [Test]
+ public void PythonThreadIDStable()
+ {
+ long pythonThreadID = 0;
+ long pythonThreadID2 = 0;
+ var asyncCall = Task.Factory.StartNew(() =>
+ {
+ using (Py.GIL())
+ {
+ Interlocked.Exchange(ref pythonThreadID, (long)PythonEngine.GetPythonThreadID());
+ Interlocked.Exchange(ref pythonThreadID2, (long)PythonEngine.GetPythonThreadID());
+ }
+ });
+
+ var timeout = Stopwatch.StartNew();
+
+ IntPtr threadState = PythonEngine.BeginAllowThreads();
+ while (Interlocked.Read(ref pythonThreadID) == 0 || Interlocked.Read(ref pythonThreadID2) == 0)
+ {
+ Assert.Less(timeout.Elapsed, TimeSpan.FromSeconds(5), "thread IDs were not assigned in time");
+ }
+ PythonEngine.EndAllowThreads(threadState);
+
+ Assert.IsTrue(asyncCall.Wait(TimeSpan.FromSeconds(5)), "Async thread has not finished in time");
+
+ Assert.AreEqual(pythonThreadID, pythonThreadID2);
+ Assert.NotZero(pythonThreadID);
+ }
+
[Test]
public void InterruptTest()
{
@@ -39,26 +68,31 @@ public void InterruptTest()
return PythonEngine.RunSimpleString(@"
import time
-while True:
- time.sleep(0.2)");
+try:
+ while True:
+ time.sleep(0.2)
+except KeyboardInterrupt:
+ pass");
}
});
var timeout = Stopwatch.StartNew();
+
+ IntPtr threadState = PythonEngine.BeginAllowThreads();
while (Interlocked.Read(ref pythonThreadID) == 0)
{
Assert.Less(timeout.Elapsed, TimeSpan.FromSeconds(5), "thread ID was not assigned in time");
}
+ PythonEngine.EndAllowThreads(threadState);
- using (Py.GIL())
- {
- int interruptReturnValue = PythonEngine.Interrupt((ulong)Interlocked.Read(ref pythonThreadID));
- Assert.AreEqual(1, interruptReturnValue);
- }
+ int interruptReturnValue = PythonEngine.Interrupt((ulong)Interlocked.Read(ref pythonThreadID));
+ Assert.AreEqual(1, interruptReturnValue);
+ threadState = PythonEngine.BeginAllowThreads();
Assert.IsTrue(asyncCall.Wait(TimeSpan.FromSeconds(5)), "Async thread was not interrupted in time");
+ PythonEngine.EndAllowThreads(threadState);
- Assert.AreEqual(-1, asyncCall.Result);
+ Assert.AreEqual(0, asyncCall.Result);
}
}
}
diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs
index 4b72dabd7..cd608fe93 100644
--- a/src/runtime/pythonengine.cs
+++ b/src/runtime/pythonengine.cs
@@ -570,8 +570,9 @@ internal static void Exec(string code, BorrowedReference globals, BorrowedRefere
/// The Python thread ID.
public static ulong GetPythonThreadID()
{
- dynamic threading = Py.Import("threading");
- return threading.InvokeMethod("get_ident");
+ using PyObject threading = Py.Import("threading");
+ using PyObject id = threading.InvokeMethod("get_ident");
+ return id.As();
}
///