我开始使用 std::mutexes 来停止一个线程并等待另一个线程恢复它。它是这样工作的:
// Ensures the mutex will be locked
while(myWaitMutex.try_lock());
// Locks it again to pause this thread
myWaitMutex.lock();
Run Code Online (Sandbox Code Playgroud)
// Executed when thread 1 should resume processing:
myWaitMutex.unlock();
Run Code Online (Sandbox Code Playgroud)
但是我不确定这是否正确并且在所有平台上都可以正常工作。如果这不正确,那么在 C++11 中实现它的正确方法是什么?
我已经定义了一个类,它有std::mutex my_mutex它的私有成员变量。但是当我尝试lock_guard在从不同线程调用的成员函数中使用它时,编译器会抛出很多错误。如果我将这个互斥锁保留在课堂之外,它就可以工作。代码如下
class ThreadClass
{
std::mutex my_mutex;
public:
void addToList(int max, int interval)
{
std::lock_guard<std::mutex> guard(my_mutex);
for (int i = 0; i < max; i++)
{
// Some operation
}
}
};
int main()
{
std::thread ct(&ThreadClass::addToList,ThreadClass(),100,1);
std::thread ct2(&ThreadClass::addToList,ThreadClass(),100,10);
std::thread ct3(&ThreadClass::print,ThreadClass());
ct.join();
ct2.join();
ct3.join();
}
Run Code Online (Sandbox Code Playgroud)
如果相同的my_mutex内容被排除在课堂之外,那么它就可以正常工作。那么当同一个变量在类中并在线程作用的成员函数中调用时,它是否像静态成员一样对待?
该pthread_mutex_init()函数在无法初始化互斥锁时返回一个非零值,而std::mutexC++11 中的类的构造函数为noexcept.
假设一个人选择在 pthreads 互斥体之上实现一个 C++ 互斥体类。他在类中包装了一个 pthread 互斥锁,并尝试通过在构造函数中调用 pthread_mutex_init() 来初始化它。如果函数调用返回非零值,表示错误,则无法立即报告错误,因为构造函数无法抛出。一种替代方法是抛出异常,直到在互斥锁上实际调用锁定方法。但这种方法似乎是错误的。
有没有另一种方法可以做到这一点,使用一些聪明的技巧来保证初始化互斥锁总是成功的?
更新:我将在这个问题上回答我自己的问题。根据语言标准,在 30.4.1.3 pge 1163 中,它说“如果互斥类型的对象初始化失败,将抛出 system_error 类型的异常。”
而 noexcept 的函数可以在函数体内抛出,只是调用者无法捕获异常。如果在 noexcept 函数内抛出异常,则将调用 std::terminate。
似乎 CRITICAL_SECTION 性能在 Windows 8 及更高版本上变得更糟。(见下图)
测试非常简单:一些并发线程每个执行 300 万个锁来独占访问一个变量。您可以在问题底部找到 C++ 程序。我在 Windows Vista、Windows 7、Windows 8、Windows 10(x64、VMWare、Intel Core i7-2600 3.40GHz)上运行测试。
结果如下图所示。X 轴是并发线程数。Y 轴是以秒为单位的经过时间(越低越好)。
我们可以看到:
SRWLock 所有平台的性能大致相同CriticalSection 性能在 Windows 8 及更高版本上相对 SRWL 变差 问题是:谁能解释为什么 CRITICAL_SECTION 性能在 Win8 及更高版本上变得更糟?
一些注意事项:
std::mutexWindows Vista 的实现基于CRITICAL_SECTION,但 Win7 和更高版本std::mutex的实现基于 SWRL。它对 MSVS17 和 15 都是正确的(确保primitives.h在 MSVC++ 安装时搜索文件并查找stl_critical_section_vista和stl_critical_section_win7类)这解释了 Win Vista 和其他系统上 std::mutex 性能之间的差异。std::mutex是一个包装器,因此相对于 …我有一个线程需要阻塞,直到另一个线程发生某些事情。这听起来很典型,我有这个解决方案。
//thread 1
mux.lock();
//send work to another thread
mux.lock(); //will likely block which I want
//thread 2
//get the work sent over from thread 1
//work on it, then
mux.unlock(); //unblock thread 1 - all good
Run Code Online (Sandbox Code Playgroud)
这似乎在 Linux 上运行良好,并且不需要条件变量 - 除了 C++ 标准说在同一线程中两次获取锁是未定义的行为 - 我在线程 1 中这样做。
我有一个场景,共享内存区域由两个不同的进程专门访问.当我启动进程时,第一个进程成功锁定互斥锁,更新内存并解锁互斥锁.但我观察到当第二个进程试图锁定它时,它仍处于死锁状态,等待互斥锁解锁.
对于第一个和第二个进程,互斥锁之间的时间差为10秒.
我使用的是std :: mutex.请告诉我我错过了什么.
我的 C++ 文件如下:
class LogMessage {
public:
LogMessage(const char* file, int line)
:
#ifdef __ANDROID__
log_stream_(std::cout)
#else
log_stream_(std::cerr)
#endif
{
std::unique_lock<std::mutex> lk(mu_);
log_stream_ << "[" << pretty_date_.HumanDate() << "] " << file << ":"
<< line << ": ";
}
~LogMessage() { log_stream_ << "\n"; }
std::ostream& stream() { return log_stream_; }
protected:
std::ostream& log_stream_;
private:
DateLogger pretty_date_;
mutable std::mutex mu_;
LogMessage(const LogMessage&);
void operator=(const LogMessage&);
};
Run Code Online (Sandbox Code Playgroud)
当我在 Ubuntu 上编译它时
g++ -std=c++11 -msse2 -fPIC -O3 -ggdb -Wall -finline-functions -I./src -I./include …
阅读文本,因为std::condition_variable我遇到了这句话:
即使共享变量是原子的,也必须在互斥锁下进行修改,才能将修改正确发布到等待线程。
我的问题是这样的:
如果不是“与 POD 一起工作的无锁代码”,原子有什么用?
更新
看起来我的问题有些混乱:(
引用文本中的“共享变量”与“条件变量”不同。请参阅同一页面中的此引用:
...直到另一个线程同时修改共享变量(条件),并通知condition_variable
请不要回答“为什么我们需要使用带有条件变量的互斥锁”或“条件等待如何工作”,而是提供有关互斥锁的使用如何“正确发布”对等待线程的原子修改的信息,即是否需要在互斥锁下完成像++counter;(而不是像测试if(counter == 0))这样的表达式?