meganz / mingw-std-threads

Standard threads implementation currently still missing on MinGW GCC on Windows
BSD 2-Clause "Simplified" License
439 stars 137 forks source link

AcquireSRWLockExclusive was not declared #58

Closed phma closed 5 years ago

phma commented 5 years ago

I'm trying to port a multithreading program to Windows 10. It works fine in Linux and DragonFly BSD, and I got it to compile, run, and show its window in Windows. But attempting to load a file (which is done by a thread) resulted in nothing happening. I ran it in gdb and found that Qt's threads were apparently acting normally, but mine were not running the thread function. I modified it to use mingw-std-threads; after I fixed the namespace issues, these compile errors remain:

In file included from C:/Users/phma/src/perfecttin/threads.h:26,
                 from C:/Users/phma/src/perfecttin/gui.cpp:30:
C:/Users/phma/src/mingw-std-threads/mingw.mutex.h: In member function 'void mingw_stdthread::windows7::mutex::lock()':
C:/Users/phma/src/mingw-std-threads/mingw.mutex.h:179:9: error: 'AcquireSRWLockExclusive' was not declared in this scope
         AcquireSRWLockExclusive(&mHandle);
         ^~~~~~~~~~~~~~~~~~~~~~~
C:/Users/phma/src/mingw-std-threads/mingw.mutex.h:179:9: note: suggested alternative: 'RpcSsContextLockExclusive'
         AcquireSRWLockExclusive(&mHandle);
         ^~~~~~~~~~~~~~~~~~~~~~~
         RpcSsContextLockExclusive
C:/Users/phma/src/mingw-std-threads/mingw.mutex.h: In member function 'void mingw_stdthread::windows7::mutex::unlock()':
C:/Users/phma/src/mingw-std-threads/mingw.mutex.h:189:9: error: 'ReleaseSRWLockExclusive' was not declared in this scope
         ReleaseSRWLockExclusive(&mHandle);
         ^~~~~~~~~~~~~~~~~~~~~~~
C:/Users/phma/src/mingw-std-threads/mingw.mutex.h:189:9: note: suggested alternative: 'RpcSsContextLockExclusive'
         ReleaseSRWLockExclusive(&mHandle);
         ^~~~~~~~~~~~~~~~~~~~~~~
         RpcSsContextLockExclusive
C:/Users/phma/src/mingw-std-threads/mingw.mutex.h: In member function 'bool mingw_stdthread::windows7::mutex::try_lock()':
C:/Users/phma/src/mingw-std-threads/mingw.mutex.h:198:20: error: 'TryAcquireSRWLockExclusive' was not declared in this scope
         BOOL ret = TryAcquireSRWLockExclusive(&mHandle);
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~
C:/Users/phma/src/mingw-std-threads/mingw.mutex.h:198:20: note: suggested alternative: 'RpcSsContextLockExclusive'
         BOOL ret = TryAcquireSRWLockExclusive(&mHandle);
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~
                    RpcSsContextLockExclusive
In file included from C:/Users/phma/src/perfecttin/threads.h:27,
                 from C:/Users/phma/src/perfecttin/gui.cpp:30:
C:/Users/phma/src/mingw-std-threads/mingw.shared_mutex.h: In member function 'void mingw_stdthread::windows7::shared_mutex::lock_shared()':
C:/Users/phma/src/mingw-std-threads/mingw.shared_mutex.h:223:9: error: 'AcquireSRWLockShared' was not declared in this scope
         AcquireSRWLockShared(native_handle());
         ^~~~~~~~~~~~~~~~~~~~
C:/Users/phma/src/mingw-std-threads/mingw.shared_mutex.h:223:9: note: suggested alternative: 'RpcSsContextLockShared'
         AcquireSRWLockShared(native_handle());
         ^~~~~~~~~~~~~~~~~~~~
         RpcSsContextLockShared
C:/Users/phma/src/mingw-std-threads/mingw.shared_mutex.h: In member function 'void mingw_stdthread::windows7::shared_mutex::unlock_shared()':
C:/Users/phma/src/mingw-std-threads/mingw.shared_mutex.h:228:9: error: 'ReleaseSRWLockShared' was not declared in this scope
         ReleaseSRWLockShared(native_handle());
         ^~~~~~~~~~~~~~~~~~~~
C:/Users/phma/src/mingw-std-threads/mingw.shared_mutex.h:228:9: note: suggested alternative: 'ReleaseSemaphore'
         ReleaseSRWLockShared(native_handle());
         ^~~~~~~~~~~~~~~~~~~~
         ReleaseSemaphore
C:/Users/phma/src/mingw-std-threads/mingw.shared_mutex.h: In member function 'bool mingw_stdthread::windows7::shared_mutex::try_lock_shared()':
C:/Users/phma/src/mingw-std-threads/mingw.shared_mutex.h:235:16: error: 'TryAcquireSRWLockShared' was not declared in this scope
         return TryAcquireSRWLockShared(native_handle()) != 0;
                ^~~~~~~~~~~~~~~~~~~~~~~
[4/5] Building CXX object CMakeFiles/perfecttin-gui.dir/mainwindow.cpp.obj

I'm using these versions:

cmake version 3.14.5
gcc.exe (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0
nmcclatchey commented 5 years ago

This would typically occur if an unusually early version of Windows were requested (and the mechanisms for selecting an XP-compatible mutex were bypassed). It might also occur if you were using a Windows API header from Windows Vista or XP.

The most likely scenario is that a Qt header also pulls in all or part of windows.h, but requests a different Windows version when it does so. Are you setting _WIN32_WINNT at the command-line or #defining it? The latter is prone to header inclusion order problems.

With that in mind, I have a few questions:

phma commented 5 years ago

I don't know how to request a version of Windows.

I am not setting _WIN32_WINNT to anything. I am compiling on Windows 10 and running on the same computer.

The namespace issue was that mingw-std-threads declares both std::mutex and mingw_stdthread::mutex, so just mutex was ambiguous. I fixed this as follows:

using namespace std;
#ifdef __MINGW64__
using namespace mingw_stdthread;
namespace th=mingw_stdthread;
#else
namespace th=std;
#endif
namespace cr=std::chrono;

th::shared_mutex wingEdge; // Lock this while changing pointers in the winged edge structure.
map<int,th::mutex> triMutex; // Lock this while locking or unlocking triangles.
th::shared_mutex holderMutex; // for triangleHolders
th::mutex adjLog;
th::mutex actMutex;
th::mutex bucketMutex;

The Qt scenario looks like what's happening, as the error occurs when compiling gui.cpp, not when compiling threads.cpp. The headers of gui.cpp are:

#include <QtGui>
#include <QtWidgets>
#include <QTranslator>
#include <iostream>
#include "point.h"
#include "octagon.h"
#include "config.h"
#include "mainwindow.h"
#include "threads.h"

gui.cpp calls startThreads, which is declared in threads.h, but gui.cpp does not itself lock or unlock anything. There is one .cpp file which both includes Qt and locks a mutex, namely tincanvas.cpp. How do I fix it?

I don't know if GCC uses the latest headers. How do I find out? I installed it with Chocolatey.

nmcclatchey commented 5 years ago

Though I do not have access to your build, I suspect that Qt might be defining the macros that request a different version of Windows. If they do this improperly, then it can cause this library to think that it has access to Windows 7 (for example) even though the headers have only provided Windows XP functions.

Try rearranging your include order.

On the topic of namespaces: Just use the one in std. It's the correct one. The other namespace exists only so that someone who already has std::thread can use this library (for performance comparisons, as an example).

P.S. The errors that you are seeing should only occur if a macro for selecting a Windows version is defined. In particular, the macro _WIN32_WINNT will cause WINVER to be defined (by the Windows headers), and WINVER is in turn used to select which Windows API features to use. If WINVER is assigned a large enough value, the library switches to using more recent (more efficient) features. For you to have seen this particular error, WINVER must be at least 0x0600.

phma commented 5 years ago

I rearranged the include files (putting threads.h before the Qt headers) and got it to compile and run the thread function. However, all threads are running as thread number 0.

void startThreads(int n)
{
  int i,m;
  threadCommand=TH_WAIT;
  threadStatus.resize(n);
  heldTriangles.resize(n);
  sleepTime.resize(n);
  initTempPointlist(n);
  mtxSquareSize=ceil(sqrt(33*n));
  m=mtxSquareSize*mtxSquareSize;
  for (i=0;i<m;i++)
    triMutex[i];
  for (i=0;i<n;i++)
    threads.push_back(th::thread(TinThread(),i));
}

A stack trace in what should be thread 2 looks like this:

#0  0x00007fff280bc6e4 in ntdll!ZwDelayExecution ()
   from C:\Windows\SYSTEM32\ntdll.dll
#1  0x00007fff25ac6931 in SleepEx () from C:\Windows\System32\KernelBase.dll
#2  0x000000000043d50a in mingw_stdthread::this_thread::sleep_for<long long, std::ratio<1ll, 1000ll> > (sleep_duration=...)
    at C:/Users/phma/src/mingw-std-threads/mingw.thread.h:279
#3  0x0000000000424f0a in sleep (thread=0)
    at C:/Users/phma/src/perfecttin/threads.cpp:246
#4  0x000000000042626a in TinThread::operator() (this=0x27770570, thread=0)
    at C:/Users/phma/src/perfecttin/threads.cpp:513
#5  0x0000000000469d3d in std::__invoke_impl<void, TinThread, int&> (__f=...,
    __args#0=@0x120fa6c: 0)
    at C:/ProgramData/chocolatey/lib/mingw/tools/install/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/invoke.h:60
#6  0x000000000046df97 in std::__invoke<TinThread, int&> (__fn=...,
    __args#0=@0x120fa6c: 0)
    at C:/ProgramData/chocolatey/lib/mingw/tools/install/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/invoke.h:95
#7  0x000000000046d3b9 in std::invoke<TinThread, int&> (__fn=...,
    __args#0=@0x120fa6c: 0)
    at C:/ProgramData/chocolatey/lib/mingw/tools/install/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/functional:81
#8  0x000000000043da07 in mingw_stdthread::detail::ThreadFuncCall<TinThread, int&>::callFunc<0ull> (this=0x27770570)
    at C:/Users/phma/src/mingw-std-threads/mingw.thread.h:82
#9  0x000000000043d9b7 in mingw_stdthread::detail::ThreadFuncCall<TinThread, int&>::callFunc (this=0x27770570)
    at C:/Users/phma/src/mingw-std-threads/mingw.thread.h:90
#10 0x000000000043da96 in mingw_stdthread::thread::threadfunc<mingw_stdthread::detail::ThreadFuncCall<TinThread, int&> > (arg=0x27770570)
    at C:/Users/phma/src/mingw-std-threads/mingw.thread.h:138
#11 0x00007fff2706b04a in msvcrt!_beginthreadex ()
   from C:\Windows\System32\msvcrt.dll
#12 0x00007fff2706b11c in msvcrt!_endthreadex ()
   from C:\Windows\System32\msvcrt.dll
#13 0x00007fff27107bd4 in KERNEL32!BaseThreadInitThunk ()
   from C:\Windows\System32\kernel32.dll
#14 0x00007fff2808ce71 in ntdll!RtlUserThreadStart ()
   from C:\Windows\SYSTEM32\ntdll.dll
(gdb) frame 8
#8  0x000000000043da07 in mingw_stdthread::detail::ThreadFuncCall<TinThread, int&>::callFunc<0ull> (this=0x27770570)
    at C:/Users/phma/src/mingw-std-threads/mingw.thread.h:82
82                  detail::invoke(std::forward<Func>(mFunc), std::get<S>(std::forward<Tuple>(mArgs)) ...);
(gdb) print mArgs
$3 = std::tuple containing = {[1] = @0x120fa6c}
(gdb) print *(int *)0x120fa6c
$4 = 0
(gdb) print *(int *)0x120fa70
$5 = 60

The 0 appears to be what's passed to the thread function; it should be 2. The 60 is I don't know what.

The program is working well enough now that I can work around this problem.

nmcclatchey commented 5 years ago

Thank you for bringing this up; it appears that arguments are being passed by reference rather than copied, even if the function requests them by value. I'll add a regression test and see what I can do to address this.