Home Dashboard Directory Help
Search

VS2011 Beta fires assertion about unlocking of unowned mutex by ixSci


Status: 

Closed
 as Fixed Help for as Fixed


2
0
Sign in
to vote
Type: Bug
ID: 735224
Opened: 4/3/2012 4:58:18 AM
Access Restriction: Public
Moderator Decision: Sent to Engineering Team for consideration
0
Workaround(s)
view
1
User(s) can reproduce this bug

Description

Given the following code:

#include <thread>
#include <mutex>
#include <condition_variable>

std::condition_variable g_Condition;
std::mutex g_Mutex;

int main()
{
    auto call = []()
    {
        std::unique_lock<std::mutex> lock(g_Mutex);
        std::this_thread::sleep_for(std::chrono::seconds(5));
        std::notify_all_at_thread_exit(g_Condition, std::move(lock));
    };
    std::thread callThread(call);
    callThread.detach();
    std::unique_lock<std::mutex> lock(g_Mutex);
    g_Condition.wait(lock);
    return 0;
}

VS2011 constantly fires assertion "f:\dd\vctools\crt_bld\self_64_amd64\crt\src\thr\mutex.c(140): unlock of unowned mutex"
Details
Sign in to post a comment.
Posted by Microsoft on 4/27/2012 at 9:18 PM
Hi,

Thanks for reporting this bug. We've fixed it, and the fix will be available in VC11 RTM.

Please note that your original repro had a couple of problems:

1. The main thread constructed the second thread before acquiring the lock. This would allow the second thread to jump in, acquire the lock, sleep, and notify_all_at_thread_exit() before the main thread called wait() on the condition_variable.

2. cv.wait(lock) can unblock spuriously, according to the Standard.

The following repro fixes those problems:

C:\Temp>type meow.cpp
#include <stdio.h>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <utility>
using namespace std;

int main() {
    printf("%02d.%02d.%05d.%02d\n", _MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 100000, _MSC_BUILD);

    mutex m;
    condition_variable cv;
    bool b = false;

    puts("Main thread: Locking m.");
    unique_lock<mutex> lock1(m);

    puts("Main thread: Constructing t.");
    thread t([&]() {
        puts("Second thread: Locking m.");
        unique_lock<mutex> lock2(m);

        puts("Second thread: Sleeping...");
        this_thread::sleep_for(chrono::seconds(5));

        puts("Second thread: Setting b to true.");
        b = true;

        puts("Second thread: Calling notify_all_at_thread_exit().");
        notify_all_at_thread_exit(cv, move(lock2));

        puts("Second thread: Bye!");
    });

    puts("Main thread: Unlocking m, waiting for cv.");
    cv.wait(lock1, [&]() { return b; });

    puts("Main thread: Joining t.");
    t.join();

    puts("Main thread: Bye!");
}

C:\Temp>cl /EHsc /nologo /W4 /MTd meow.cpp
meow.cpp

Before the fix, this emitted:

C:\Temp>meow
17.00.50420.00
Main thread: Locking m.
Main thread: Constructing t.
Second thread: Locking m.
Main thread: Unlocking m, waiting for cv.
Second thread: Sleeping...
Second thread: Setting b to true.
Second thread: Calling notify_all_at_thread_exit().
Second thread: Bye!
d:\wincstl0x\vctools\crt_bld\self_x86\crt\src\thr\mutex.c(131): unlock of unowned mutex
---------------------------
Microsoft Visual C++ Runtime Library
---------------------------
Debug Error!

Program: C:\Temp\meow.exe

R6010 - abort() has been called

(Press Retry to debug the application)

---------------------------
Abort Retry Ignore
---------------------------

After the fix, this succeeds:

C:\Temp>meow
17.00.50426.01
Main thread: Locking m.
Main thread: Constructing t.
Second thread: Locking m.
Main thread: Unlocking m, waiting for cv.
Second thread: Sleeping...
Second thread: Setting b to true.
Second thread: Calling notify_all_at_thread_exit().
Second thread: Bye!
Main thread: Joining t.
Main thread: Bye!

C:\Temp>

If you have any further questions, feel free to E-mail me at stl@microsoft.com .

Stephan T. Lavavej
Visual C++ Libraries Developer
Posted by Shane Powell NZ on 4/24/2012 at 2:34 PM
I can also produce this bug as will with the following code:

#include <iostream>
#include <thread>
#include <future>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    promise<int> test_promise;
    auto f = test_promise.get_future();

    thread x([&]
    {
        test_promise.set_value_at_thread_exit(10);
    });

    int i = f.get();

    cout << "i = " << i << endl;

    x.join();

    return 0;
}


Looking into the promise implementation it is using the condition_variable doing basically the same as the first example.
Posted by Microsoft on 4/3/2012 at 11:11 PM
Thanks for your feedback.

We are rerouting this issue to the appropriate group within the Visual Studio Product Team for triage and resolution. These specialized experts will follow-up with your issue.
Posted by MS-Moderator07 [Feedback Moderator] on 4/3/2012 at 8:34 PM

#include <thread>
#include <mutex>
#include <condition_variable>

std::condition_variable g_Condition;
std::mutex g_Mutex;

int main()
{
    auto call = []()
    {
        std::unique_lock<std::mutex> lock(g_Mutex);
        std::this_thread::sleep_for(std::chrono::seconds(5));
        std::notify_all_at_thread_exit(g_Condition, std::move(lock));
    };
    std::thread callThread(call);
    callThread.detach();
    std::unique_lock<std::mutex> lock(g_Mutex);
    g_Condition.wait(lock);
    return 0;
}
Posted by MS-Moderator01 on 4/3/2012 at 5:46 AM
Thank you for your feedback, we are currently reviewing the issue you have submitted. If this issue is urgent, please contact support directly(http://support.microsoft.com)
Sign in to post a workaround.