You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Windows] _thread.start_new_thread() should close the thread handle #88602
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee=Noneclosed_at=<Date2021-06-16.16:03:07.236>created_at=<Date2021-06-16.15:43:23.535>labels= ['invalid', 'OS-windows', '3.11']
title='[Windows] _thread.start_new_thread() should close the thread handle'updated_at=<Date2021-06-16.16:03:07.236>user='https://github.com/vstinner'
_thread.start_new_thread() is implemented by calling _beginthreadex().
Currently, when the thread completes: PyThread_exit_thread() is called which calls "_endthreadex(0)" on Windows. I proposed to no longer call it explicitly in bpo-44434.
_endthreadex() documentation says that the thread handle must be closed explicitly (with CloseHandle()), same applies for ExitThread().
"Unlike _endthread, the _endthreadex function does not close the thread handle, thereby allowing other threads to block on this one without fear that the handle will be freed out from under the system."
_endthread() closes the thread handle, but Python uses _endthreadex().
Should Python be modified to close explicitly the thread handle once the thread terminated?
Would it be safe to close the handle just after PyThread_start_new_thread() success?
Or should it be done in the C function thread_run(), just before existing, CloseHandle(GetCurrentThread())?
To debug this issue, GetHandleInformation() can be used to check if the handle is still open or not. For example, call os.get_handle_inheritable(handle) in Python.
It seems like the handle returned by _beginthreadex() cannot be used with SuspendThread() or ResumeThread(): both fail. GetHandleInformation() also fails on this handle (I tried os.get_handle_inheritable()).
Activity
vstinner commentedon Jun 16, 2021
_thread.start_new_thread() is implemented by calling _beginthreadex().
Currently, when the thread completes: PyThread_exit_thread() is called which calls "_endthreadex(0)" on Windows. I proposed to no longer call it explicitly in bpo-44434.
_endthreadex() documentation says that the thread handle must be closed explicitly (with CloseHandle()), same applies for ExitThread().
"Unlike _endthread, the _endthreadex function does not close the thread handle, thereby allowing other threads to block on this one without fear that the handle will be freed out from under the system."
_endthread() closes the thread handle, but Python uses _endthreadex().
Should Python be modified to close explicitly the thread handle once the thread terminated?
_endthread() and _endthreadex() documentation:
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/endthread-endthreadex?view=msvc-160
Example closing the thread handle in the thread which created the thread:
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/beginthread-beginthreadex?view=msvc-160
Simplified code:
---
Would it be safe to close the handle just after PyThread_start_new_thread() success?
Or should it be done in the C function thread_run(), just before existing, CloseHandle(GetCurrentThread())?
To debug this issue, GetHandleInformation() can be used to check if the handle is still open or not. For example, call os.get_handle_inheritable(handle) in Python.
eryksun commentedon Jun 16, 2021
We already close the handle in PyThread_start_new_thread() in Python/thread_nt.h:
vstinner commentedon Jun 16, 2021
This is useless. GetCurrentThread() returns a pseudo handle. The GetCurrentThread() documentation says:
"The pseudo handle need not be closed when it is no longer needed. Calling the CloseHandle function with this handle has no effect."
vstinner commentedon Jun 16, 2021
So far, I'm not convinced that Python must be changed.
I modified my Python locally so thread_run() writes GetCurrentThread() to stderr.
Example:
---
Output:
---
start_new_thread() -> 2436
SuspendThread(2436) -> 4294967295
ResumeThread(2436) -> 4294967295
thread_run: GetCurrentThread() -> -2
--thread exit--
SuspendThread(2436) -> 4294967295
ResumeThread(2436) -> 4294967295
---
It seems like the handle returned by _beginthreadex() cannot be used with SuspendThread() or ResumeThread(): both fail. GetHandleInformation() also fails on this handle (I tried os.get_handle_inheritable()).
vstinner commentedon Jun 16, 2021
Eryk:
Oh right! I completely missed this call. Thanks for double checking the issue ;-) I close the issue as "not a bug".