I started using boost::thread recently (WinXP, VS10, BoostPro) and found that mutex can be unlocked by any thread, not by the thread that owns it only.
Additionally it seams that the basic lock_guard + mutex combo is doing some internal counting of multiple lock() and unlock() but it is not a big issue I guess.
Does somebody know why it was designed in such a way? Is it on purpose?
(or maybe there is something wrong with my build environment / libs?)
Example app:
#include
#include
using namespace std;
class NamedThread
{
public:
NamedThread(string name_, boost::mutex& mtx_) :
mtx(mtx_), name(name_) {}
void operator ()()
{
for (int i = 0; i < 10; ++i)
{
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
cout << name << endl;
//boost::lock_guard<:mutex> guard1(mtx);
//boost::lock_guard<:mutex> guard2(mtx);
boost::unique_lock<:mutex> guard1(mtx);
boost::unique_lock<:mutex> guard2(mtx);
}
}
string name;
boost::mutex& mtx;
};
class UnlockerThread
{
public:
UnlockerThread(string name_, boost::mutex& mtx_) :
mtx(mtx_), name(name_) {}
void operator ()()
{
for (int i = 0; i < 100; ++i)
{
boost::this_thread::sleep(boost::posix_time::milliseconds(3000));
cout << name << ": unlocking" << endl;
mtx.unlock(); // !!! IT WORKS !!!
}
}
string name;
boost::mutex& mtx;
};
int main()
{
boost::mutex mtx;
NamedThread th2("Thread1", mtx);
boost::thread t2(th2);
UnlockerThread th3("UnlockerThread", mtx);
boost::thread t3(th3);
t2.join();
char ch;
cin >> ch;
return 0;
}
Thanks,
解决方案
The boost documentation is very clear that a precondition for calling mutex.unlock is that "the current thread owns *this." That doesn't mean that violating that precondition will result in an exception/error/crash (although it might be nice for a debug build), but you can't rely on any specific behaviour in that case.
The win32 implementation appears to implement most of the logic for a mutex using atomic instructions - presumably this is because of limited support for more complex mutex types (recursive/timed) on win32. Win32's native critical sections can only be used for simple mutexes (and Win32's native mutexes are too heavyweight for in-process mutexes).