Re: [Mingw-w64-public] Fwd: [patch] Reimplement GNU threads library on native Windows
> 0) complexifies comparison of thread IDs without obvious benefits, and The reverse argument is also true: using IDs would complexify everything else with the only benefit of simplifying the equal primitive. > 1) does not work reliably because handles can be duplicated, and That's pure FUD. > 2) makes `__gthread_self()` return invalid handles in detached threads. Admittedly, but this can be fixed if this is deemed necessary by clearing the thread descriptor when detaching the thread. -- Eric Botcazou
Re: [Mingw-w64-public] Fwd: [patch] Reimplement GNU threads library on native Windows
在 2019/7/29 22:43, JonY 写道: > > Any updates? > No. I am still under the impression that using thread handles as `std::thread::id`s: 0) complexifies comparison of thread IDs without obvious benefits, and 1) does not work reliably because handles can be duplicated, and 2) makes `__gthread_self()` return invalid handles in detached threads. -- Best regards, LH_Mouse signature.asc Description: OpenPGP digital signature
Re: [Mingw-w64-public] Fwd: [patch] Reimplement GNU threads library on native Windows
On 7/3/19 12:55 PM, Liu Hao wrote: > 在 2019/7/2 下午8:27, Jonathan Wakely 写道: >> >> What do you mean by "unclosed thread"? If I read it correctly, the MSDN >> page >> refers to closing a handle (which makes sense), not closing a thread. >> > > Yes, it meant a thread which has terminated but not deleted due to some > handles left open. > > >>> This could also mean that there is no effect way to denote a thread >>> uniquely. As a consequence libstdc++ may have to its own bookkeeping >>> mechanism. >> >> As I said in my last mail, libstdc++ does not need a way to denote a >> thread uniquely. >> > > At my last glance at the `__gthread_` interfaces, libstdc++ requires > thread IDs to be LessThanComparable, which would require retrieval of > thread IDs by handle, as in `__gthread_equal()`. > > More than that, if my previous vision was correct (a terminated thread > has no ID associated) then `GetThreadId()` on a thread that has > terminated would not return a valid thread ID. Fortunately, this seems > not the case: > > ```c > #include > #include > > DWORD __stdcall ThreadProc(void* pParam) > { > printf("thread %lu running\n", GetCurrentThreadId()); > return 0; > } > > int main(void) > { > HANDLE hThread = CreateThread(0, 0, ThreadProc, 0, CREATE_SUSPENDED, 0); > printf("thread %lu created\n", GetThreadId(hThread)); > > ResumeThread(hThread); > WaitForSingleObject(hThread, INFINITE); > printf("thread %lu terminated\n", GetThreadId(hThread)); > > CloseHandle(hThread); > // `hThread` is now invalid; DO NOT PLAY WITH THIS AT HOME! > printf("thread %lu closed\n", GetThreadId(hThread)); > } > ``` > > This program outputs > > ```text > E:\Desktop>gcc test.c -Wall -Wextra -Wpedantic && a.exe > test.c: In function 'ThreadProc': > test.c:4:34: warning: unused parameter 'pParam' [-Wunused-parameter] > 4 | DWORD __stdcall ThreadProc(void* pParam) > |~~^~ > thread 9172 created > thread 9172 running > thread 9172 terminated > thread 0 closed > > E:\Desktop> > ``` > > Despite Microsoft's documentation, the identifier of a thread seems > uncollected as long as there are still handles to the thread. So it > might be safe to assume that the identifier of an `std::thread` *cannot* > be reused before it is `join()`'d or `detach()`'d which closes the > handle stored in the `std::thread` object. > > Any updates? signature.asc Description: OpenPGP digital signature
Re: [Mingw-w64-public] Fwd: [patch] Reimplement GNU threads library on native Windows
在 2019/7/2 下午8:27, Jonathan Wakely 写道: > > What do you mean by "unclosed thread"? If I read it correctly, the MSDN > page > refers to closing a handle (which makes sense), not closing a thread. > Yes, it meant a thread which has terminated but not deleted due to some handles left open. >> This could also mean that there is no effect way to denote a thread >> uniquely. As a consequence libstdc++ may have to its own bookkeeping >> mechanism. > > As I said in my last mail, libstdc++ does not need a way to denote a > thread uniquely. > At my last glance at the `__gthread_` interfaces, libstdc++ requires thread IDs to be LessThanComparable, which would require retrieval of thread IDs by handle, as in `__gthread_equal()`. More than that, if my previous vision was correct (a terminated thread has no ID associated) then `GetThreadId()` on a thread that has terminated would not return a valid thread ID. Fortunately, this seems not the case: ```c #include #include DWORD __stdcall ThreadProc(void* pParam) { printf("thread %lu running\n", GetCurrentThreadId()); return 0; } int main(void) { HANDLE hThread = CreateThread(0, 0, ThreadProc, 0, CREATE_SUSPENDED, 0); printf("thread %lu created\n", GetThreadId(hThread)); ResumeThread(hThread); WaitForSingleObject(hThread, INFINITE); printf("thread %lu terminated\n", GetThreadId(hThread)); CloseHandle(hThread); // `hThread` is now invalid; DO NOT PLAY WITH THIS AT HOME! printf("thread %lu closed\n", GetThreadId(hThread)); } ``` This program outputs ```text E:\Desktop>gcc test.c -Wall -Wextra -Wpedantic && a.exe test.c: In function 'ThreadProc': test.c:4:34: warning: unused parameter 'pParam' [-Wunused-parameter] 4 | DWORD __stdcall ThreadProc(void* pParam) |~~^~ thread 9172 created thread 9172 running thread 9172 terminated thread 0 closed E:\Desktop> ``` Despite Microsoft's documentation, the identifier of a thread seems uncollected as long as there are still handles to the thread. So it might be safe to assume that the identifier of an `std::thread` *cannot* be reused before it is `join()`'d or `detach()`'d which closes the handle stored in the `std::thread` object. -- Best regards, LH_Mouse signature.asc Description: OpenPGP digital signature
Re: [Mingw-w64-public] Fwd: [patch] Reimplement GNU threads library on native Windows
On 02/07/19 20:14 +0800, Liu Hao wrote: 在 2019/7/2 下午8:00, Jonathan Wakely 写道: The C++ standard says: "The library may reuse the value of a thread::id of a terminated thread that can no longer be joined." So that's not a reason to use a handle. According to MSDN [1] a thread ID is valid 'until the thread has been terminated' so I presume a terminated but unclosed thread does not have a thread ID. What do you mean by "unclosed thread"? If I read it correctly, the MSDN page refers to closing a handle (which makes sense), not closing a thread. This could also mean that there is no effect way to denote a thread uniquely. As a consequence libstdc++ may have to its own bookkeeping mechanism. As I said in my last mail, libstdc++ does not need a way to denote a thread uniquely. I'm not objecting to Eric's use of a HANDLE for a thread::id, as his justification makes sense. I'm just saying we don't need a unique ID that outlives the thread, because that's not a requirement. [1] https://docs.microsoft.com/en-us/windows/desktop/ProcThread/thread-handles-and-identifiers -- Best regards, LH_Mouse
Re: [Mingw-w64-public] Fwd: [patch] Reimplement GNU threads library on native Windows
在 2019/7/2 下午8:00, Jonathan Wakely 写道: > The C++ standard says: > > "The library may reuse the value of a thread::id of a terminated > thread that can no longer be joined." > > So that's not a reason to use a handle. According to MSDN [1] a thread ID is valid 'until the thread has been terminated' so I presume a terminated but unclosed thread does not have a thread ID. This could also mean that there is no effect way to denote a thread uniquely. As a consequence libstdc++ may have to its own bookkeeping mechanism. [1] https://docs.microsoft.com/en-us/windows/desktop/ProcThread/thread-handles-and-identifiers -- Best regards, LH_Mouse signature.asc Description: OpenPGP digital signature
Re: [Mingw-w64-public] Fwd: [patch] Reimplement GNU threads library on native Windows
On 02/07/19 12:15 +0200, Jacek Caban wrote: On 02/07/2019 12:12, Jacek Caban wrote: On 02/07/2019 11:57, Liu Hao wrote: 在 2019/7/2 下午5:19, Eric Botcazou 写道: It seems inappropriate to use handles as thread identifiers (as handles imply resource ownership and are not unique identifiers); thread IDs (as `DWORD` or `unsigned long`) would be a better alternative. This was considered but ultimately rejected, as you can do nothing with a thread Id, i.e. you need a handle for everything. But the __gthread_equal routine does compare the Ids and not the handles. The `OpenThread()` function can obtain a handle by thread ID. It returns a real handle that has to be closed when it is out of use. Using the pseudo handle returned by `GetCurrentThread()` may be more efficient if the target thread ID is equal to `GetCurrentThreadId()`. The problem with thread id is that it's not valid nor guaranteed to be identical after the thread is terminated. A handle needs to be used for that. I meant unique, not identical. The C++ standard says: "The library may reuse the value of a thread::id of a terminated thread that can no longer be joined." So that's not a reason to use a handle.
Re: [Mingw-w64-public] Fwd: [patch] Reimplement GNU threads library on native Windows
On 02/07/2019 12:12, Jacek Caban wrote: On 02/07/2019 11:57, Liu Hao wrote: 在 2019/7/2 下午5:19, Eric Botcazou 写道: It seems inappropriate to use handles as thread identifiers (as handles imply resource ownership and are not unique identifiers); thread IDs (as `DWORD` or `unsigned long`) would be a better alternative. This was considered but ultimately rejected, as you can do nothing with a thread Id, i.e. you need a handle for everything. But the __gthread_equal routine does compare the Ids and not the handles. The `OpenThread()` function can obtain a handle by thread ID. It returns a real handle that has to be closed when it is out of use. Using the pseudo handle returned by `GetCurrentThread()` may be more efficient if the target thread ID is equal to `GetCurrentThreadId()`. The problem with thread id is that it's not valid nor guaranteed to be identical after the thread is terminated. A handle needs to be used for that. I meant unique, not identical. Jacek
Re: [Mingw-w64-public] Fwd: [patch] Reimplement GNU threads library on native Windows
On 02/07/2019 11:57, Liu Hao wrote: 在 2019/7/2 下午5:19, Eric Botcazou 写道: It seems inappropriate to use handles as thread identifiers (as handles imply resource ownership and are not unique identifiers); thread IDs (as `DWORD` or `unsigned long`) would be a better alternative. This was considered but ultimately rejected, as you can do nothing with a thread Id, i.e. you need a handle for everything. But the __gthread_equal routine does compare the Ids and not the handles. The `OpenThread()` function can obtain a handle by thread ID. It returns a real handle that has to be closed when it is out of use. Using the pseudo handle returned by `GetCurrentThread()` may be more efficient if the target thread ID is equal to `GetCurrentThreadId()`. The problem with thread id is that it's not valid nor guaranteed to be identical after the thread is terminated. A handle needs to be used for that. Jacek
Re: [Mingw-w64-public] Fwd: [patch] Reimplement GNU threads library on native Windows
在 2019/7/2 下午5:19, Eric Botcazou 写道: >> It seems inappropriate to use handles as thread identifiers (as handles >> imply resource ownership and are not unique identifiers); thread IDs (as >> `DWORD` or `unsigned long`) would be a better alternative. > > This was considered but ultimately rejected, as you can do nothing with a > thread Id, i.e. you need a handle for everything. But the __gthread_equal > routine does compare the Ids and not the handles. > The `OpenThread()` function can obtain a handle by thread ID. It returns a real handle that has to be closed when it is out of use. Using the pseudo handle returned by `GetCurrentThread()` may be more efficient if the target thread ID is equal to `GetCurrentThreadId()`. -- Best regards, LH_Mouse signature.asc Description: OpenPGP digital signature
Re: [Mingw-w64-public] Fwd: [patch] Reimplement GNU threads library on native Windows
> It seems inappropriate to use handles as thread identifiers (as handles > imply resource ownership and are not unique identifiers); thread IDs (as > `DWORD` or `unsigned long`) would be a better alternative. This was considered but ultimately rejected, as you can do nothing with a thread Id, i.e. you need a handle for everything. But the __gthread_equal routine does compare the Ids and not the handles. -- Eric Botcazou
Re: [Mingw-w64-public] Fwd: [patch] Reimplement GNU threads library on native Windows
在 2019/6/29 上午12:10, Jacek Caban 写道: > > You don't really need to store the whole __gthr_win32_thr_desc in TLS. > If you stored just the handle, this wouldn't need a destructor. > > The handle to be stored in the TLS ('the Handle' for short hereinafter) should be a real handle, so there are a few scenarios that we should consider: 0) the Handle should be closed upon the spawned thread's exit; in this case a destructor is still necessary to prevent handle leaks. 1) the Handle is closed by the creator via either `*_join()` or `*_detach()`; in the latter case the Handle becomes invalid while the thread is running, so `*_self()` would return an invalid handle. It seems inappropriate to use handles as thread identifiers (as handles imply resource ownership and are not unique identifiers); thread IDs (as `DWORD` or `unsigned long`) would be a better alternative. -- Best regards, LH_Mouse signature.asc Description: OpenPGP digital signature
Re: [Mingw-w64-public] Fwd: [patch] Reimplement GNU threads library on native Windows
Hi Eric, On 6/28/19 3:42 PM, NightStrike wrote: FYI, Eric posted this today to the GCC patches list. This may be of great interest to many who would prefer native threads instead of the winpthreads posix style interface. Great work, Eric! I look forward to trying this out! -- Forwarded message - From: Eric Botcazou Date: Fri, Jun 28, 2019 at 6:51 AM Subject: [patch] Reimplement GNU threads library on native Windows To: Cc: Hi, this reimplements the GNU threads library on native Windows (except for the Objective-C specific subset) using direct Win32 API calls, in lieu of the implementation based on semaphores. This base implementations requires Windows XP/Server 2003, which is the default minimal setting of MinGW-W64. This also adds the support required for the C++11 threads, using again direct Win32 API calls; this additional layer requires Windows Vista/Server 2008 and is enabled only if _GTHREADS_USE_COND is defined to 1. This also changes libstdc++ to setting _GTHREADS_USE_COND to 1 when the switch --enable-libstdcxx-threads is passed, which means that C++11 threads are still disabled by default on native Windows and that you need to explicitly pass the switch to enable them. The 30_threads chapter of the testsuite is clean. Tested on i686-pc-mingw32 and x86_64-pc-mingw32, OK for the mainline? It's indeed great to see this. Thank you! +/* The implementation strategy for the c++0x thread support is as follows. + + A GNU thread is represented by a Win32 HANDLE that is obtained when the + Win32 thread is created, except of course for the initial thread. This + Win32 HANDLE is stored in a descriptor keyed from TLS memory for every + thread, so the self routine can return it instead of having to duplicate + the pseudo-handle returned by GetCurrentThread each time it is invoked. + For the initial thread, this Win32 HANDLE is created during the first + call to the self routine using the aforementioned technique. + + Note that the equal routine compares the identifier of threads instead + of their Win32 HANDLE, which will give the correct positive answer even + in the case where distinct Win32 HANDLEs have been created for the same + thread by multiple instances of libgcc included in the link. */ Note that this will cause handle leaks if used across multiple libgcc instances, through. +#include "gthr-win32.h" + +/* The thread descriptor keyed from TLS memory. */ +struct __gthr_win32_thr_desc +{ + void *(*func) (void*); + void *args; + HANDLE h; +}; + +/* The TLS key used by one instance of the library. */ +static __gthread_key_t __gthr_win32_tls = TLS_OUT_OF_INDEXES; + +/* The initialization device for the TLS key. */ +static __gthread_once_t __gthr_win32_tls_once = __GTHREAD_ONCE_INIT; + +/* Initialize the TLS key. */ + +static void +__gthr_win32_tls_init (void) +{ + if (__gthread_key_create (&__gthr_win32_tls, free)) +abort (); +} You don't really need to store the whole __gthr_win32_thr_desc in TLS. If you stored just the handle, this wouldn't need a destructor. Thanks, Jacek