Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么std::condition_variable::wait_for()会在使用VS2013的Windows上引发操作不允许的std::system_错误?_Windows_Multithreading_C++11_Visual C++_Visual Studio 2013 - Fatal编程技术网

为什么std::condition_variable::wait_for()会在使用VS2013的Windows上引发操作不允许的std::system_错误?

为什么std::condition_variable::wait_for()会在使用VS2013的Windows上引发操作不允许的std::system_错误?,windows,multithreading,c++11,visual-c++,visual-studio-2013,Windows,Multithreading,C++11,Visual C++,Visual Studio 2013,我有一个简单的测试,在GUI程序上有一个后台线程,它每秒异步地将显示工作推回到GUI线程上一次。它在Windows上不工作,std::condition\u variable::wait\u for()抛出类型为的std::system\u错误。 这是Windows 7 x64上的Visual Studio 2013。Linux上没有gcc,因此这里不计算-lpthread。关于这个问题的现有问题(包括堆栈溢出和其他问题)都是针对gcc/Linux/-lpthread事实上,我在Linux(使用

我有一个简单的测试,在GUI程序上有一个后台线程,它每秒异步地将显示工作推回到GUI线程上一次。它在Windows上不工作,
std::condition\u variable::wait\u for()
抛出类型为
std::system\u错误。

这是Windows 7 x64上的Visual Studio 2013。Linux上没有gcc,因此这里不计算
-lpthread
。关于这个问题的现有问题(包括堆栈溢出和其他问题)都是针对gcc/Linux/
-lpthread
事实上,我在Linux(使用GTK+)上做了一个等效的测试,效果很好

这里有一个例子。它将打开一个带有按钮和多行编辑框的窗口。每隔一秒钟,您就会看到添加到编辑框中的一行
1秒。单击按钮可立即添加说某事的行
。线不能混在一起

相反,如果运行此程序,您应该看到

class std::system_error caught: operation not permitted: operation not permitted
在命令行上,
1秒时间内传递的
消息永远不会显示

我在和你一起建房子

cl /TP wincondvartest.cpp /W4 /Zi /EHsc /link /incremental:no user32.lib kernel32.lib gdi32.lib
发生什么事了?谢谢

// 6 december 2015
#define UNICODE
#define _UNICODE
#define STRICT
#define STRICT_TYPED_ITEMIDS
// get Windows version right; right now Windows Vista
#define WINVER 0x0600               /* according to Microsoft's winnls.h */
#define _WIN32_WINNT 0x0600     /* according to Microsoft's sdkddkver.h */
#define _WIN32_WINDOWS 0x0600       /* according to Microsoft's pdh.h */
#define _WIN32_IE 0x0700            /* according to Microsoft's sdkddkver.h */
#define NTDDI_VERSION 0x06000000    /* according to Microsoft's sdkddkver.h */
#include <windows.h>
#include <thread>
#include <chrono>
#include <mutex>
#include <condition_variable>
#include <string.h>
#include <stdlib.h>
#include <typeinfo>
#include <time.h>

HWND mainwin;
std::condition_variable cv;
std::mutex m;
std::unique_lock<std::mutex> ourlock(m);
std::thread *timeThread;

bool wait(void)
try {
    return cv.wait_for(ourlock, std::chrono::seconds(1)) == std::cv_status::timeout;
} catch (const std::exception &e) {
    fprintf(stderr, "%s caught: %s\n", typeid (e).name(), e.what());
    return false;       // kill the thread
}

void threadproc(void)
{
    while (wait())
        PostMessageW(mainwin, WM_APP, 0, 0);
}

HWND edit;

void appendline(const WCHAR *wc)
{
    LRESULT n;

    n = SendMessageW(edit, WM_GETTEXTLENGTH, 0, 0);
    SendMessageW(edit, EM_SETSEL, n, n);
    SendMessageW(edit, EM_REPLACESEL, FALSE, (LPARAM) wc);
}

HWND button;

LRESULT CALLBACK wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg) {
    case WM_COMMAND:
        if (lParam == (LPARAM) button)
            appendline(L"Saying something\n");
        break;
    case WM_APP:
        appendline(L"One second passed\n");
        break;
    case WM_CLOSE:
        cv.notify_all();
        timeThread->join();
        PostQuitMessage(0);
        break;
    }
    return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}

int main(void)
{
    WNDCLASSW wc;
    RECT r;
    MSG msg;

    ZeroMemory(&wc, sizeof (WNDCLASSW));
    wc.lpszClassName = L"mainwin";
    wc.lpfnWndProc = wndproc;
    wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
    RegisterClassW(&wc);

    r.left = 0;
    r.top = 0;
    r.right = 10 + 300 + 10;
    r.bottom = 10 + 20 + 5 + 195 + 10;
    AdjustWindowRectEx(&r, WS_OVERLAPPEDWINDOW, FALSE, 0);
    mainwin = CreateWindowExW(0,
        L"mainwin", L"mainwin",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        r.right - r.left, r.bottom - r.top,
        NULL, NULL, NULL, NULL);

    button = CreateWindowExW(0,
        L"button", L"Say Something",
        BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE,
        10, 10,
        300, 20,
        mainwin, NULL, NULL, NULL);

    edit = CreateWindowExW(WS_EX_CLIENTEDGE,
        L"edit", L"",
        ES_AUTOVSCROLL | ES_LEFT | ES_MULTILINE | ES_READONLY | ES_WANTRETURN | WS_CHILD | WS_VISIBLE | WS_VSCROLL,
        10, 10 + 20 + 5,
        300, 195,
        mainwin, NULL, NULL, NULL);

    timeThread = new std::thread(threadproc);

    ShowWindow(mainwin, SW_SHOWDEFAULT);
    UpdateWindow(mainwin);

    while (GetMessageW(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }
    return 0;
}
//2015年12月6日
#定义UNICODE
#定义UNICODE
#定义严格
#定义严格的\u类型的\u项目ID
//获得正确的Windows版本;现在Windows Vista
#根据Microsoft的winnls.h定义WINVER 0x0600/**/
#根据Microsoft的sdkddkver.h定义_WIN32_WINNT 0x0600/**/
#根据Microsoft的pdh.h定义_WIN32_WINDOWS 0x0600/**/
#根据微软的sdkddkver.h定义_WIN32_IE 0x0700/**/
#根据Microsoft的sdkddkver.h定义NTDDI_版本0x06000000/**/
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
HWND mainwin;
std::条件变量cv;
std::互斥m;
std::唯一锁定ourlock(m);
std::thread*timeThread;
布尔等待(无效)
试一试{
返回cv.wait_for(ourlock,std::chrono::seconds(1))==std::cv_status::timeout;
}捕获(const std::exception&e){
fprintf(stderr,“%s捕获:%s\n”,typeid(e.name(),e.what());
返回false;//终止线程
}
void threadproc(void)
{
while(wait())
PostMessageW(mainwin,WM_应用程序,0,0);
}
HWND编辑;
无效附加线(常量WCHAR*wc)
{
LRESULT n;
n=SendMessageW(编辑,WM_GETTEXTLENGTH,0,0);
SendMessageW(编辑,EM_设置,n,n);
SendMessageW(编辑,EM_REPLACESEL,FALSE,(LPARAM)wc);
}
HWND按钮;
LRESULT回调wndproc(HWND HWND、UINT uMsg、WPARAM WPARAM、LPARAM LPARAM)
{
开关(uMsg){
case WM_命令:
if(lParam==(lParam)按钮)
附录行(L“说某事”\n);
打破
案例WM_应用程序:
附录行(L“一秒钟过去\n”);
打破
案例WM_结束:
cv.通知所有人();
timeThread->join();
PostQuitMessage(0);
打破
}
返回DefWindowProcW(hwnd、uMsg、wParam、lParam);
}
内部主(空)
{
WNDCLASSW wc;
矩形r;
味精;
零内存(&wc,sizeof(WNDCLASSW));
wc.lpszClassName=L“mainwin”;
wc.lpfnWndProc=wndproc;
wc.hbrBackground=(HBRUSH)(颜色+1);
注册分类(&wc);
r、 左=0;
r、 top=0;
r、 右=10+300+10;
r、 底部=10+20+5+195+10;
AdjustWindowRectEx(&r,WS_OVERLAPPEDWINDOW,FALSE,0);
mainwin=CreateWindowExW(0,
L“mainwin”,L“mainwin”,
WS_重叠窗口,
CW_USEDEFAULT,CW_USEDEFAULT,
r、 右-右-左,右下-右上,
空,空,空,空);
按钮=CreateWindowExW(0,
L“按钮”,L“说点什么”,
BS|U按钮| WS|U儿童| WS|U可见,
10, 10,
300, 20,
mainwin,NULL,NULL,NULL);
编辑=CreateWindowExW(WS_EX_CLIENTEDGE,
L“编辑”,L“,
自动滚动|左滚动|多行|只读|右滚动|儿童|可见|右滚动|,
10, 10 + 20 + 5,
300, 195,
mainwin,NULL,NULL,NULL);
timeThread=newstd::thread(threadproc);
ShowWindow(mainwin、SW_SHOWDEFAULT);
更新窗口(mainwin);
while(GetMessageW(&msg,NULL,0,0)){
翻译信息(&msg);
DispatchMessageW(&msg);
}
返回0;
}

您的程序试图解锁由其他线程锁定的互斥锁,从而表现出未定义的行为
ourlock
最初是在主线程上构造的,是一个全局变量,在这个点上它锁定
m
。然后将其传递到
cv。在第二个线程上等待
。这是明确禁止的:

[thread.condition.condvar]

template <class Rep, class Period>
    cv_status wait_for(unique_lock<mutex>& lock,
                       const chrono::duration<Rep, Period>& rel_time);
模板
cv_状态等待(唯一锁定和锁定,
常数时间:持续时间和相对时间);
25要求:
lock.owns\u lock()
为true,并且调用线程将
lock.mutex()
锁定


强调我的行为。

您的程序试图解锁由其他线程锁定的互斥锁,从而表现出未定义的行为
ourlock
最初是在主线程上构造的,是一个全局变量,在这个点上它锁定
m
。然后将其传递到
cv。在第二个线程上等待
。这是明确禁止的:

[thread.condition.condvar]

template <class Rep, class Period>
    cv_status wait_for(unique_lock<mutex>& lock,
                       const chrono::duration<Rep, Period>& rel_time);
模板
cv_状态等待(唯一锁定和锁定,
常数时间:持续时间和相对时间);
25要求:
lock.owns\u lock()
为true,并且调用线程将
lock.mutex()
锁定


Emphasis mine.

互斥锁最初由主线程锁定(通过
ourlock
作为全局变量)。我很确定尝试在不同的线程上解锁它是非法的,因为
cv.wait\u for(ourlock)
会尝试