C++ 一旦锁定';有空吗
我有两个线程试图锁定相同的C++ 一旦锁定';有空吗,c++,concurrency,mutex,boost-thread,C++,Concurrency,Mutex,Boost Thread,我有两个线程试图锁定相同的boost::mutex。其中一个线程持续处理某些数据,另一个线程定期显示当前状态。根据我的意图,处理线程非常频繁地释放锁并重新获取它,这样显示线程就可以在需要时点击并获取它。因此,很明显,我希望显示线程在下一次进程线程释放锁时获取锁。但是,它并没有这样做,而是等待锁,并且只在进程线程多次释放锁后才获取它 请检查说明我的问题的最小示例: #include <boost/thread.hpp> #include <iostream> using
boost::mutex
。其中一个线程持续处理某些数据,另一个线程定期显示当前状态。根据我的意图,处理线程非常频繁地释放锁并重新获取它,这样显示线程就可以在需要时点击并获取它。因此,很明显,我希望显示线程在下一次进程线程释放锁时获取锁。但是,它并没有这样做,而是等待锁,并且只在进程线程多次释放锁后才获取它
请检查说明我的问题的最小示例:
#include <boost/thread.hpp>
#include <iostream>
using namespace std;
using namespace boost;
mutex mut;
void process() {
double start = time(0);
while(1) {
unique_lock<mutex> lock(mut);
this_thread::sleep(posix_time::milliseconds(10));
std::cout<<".";
if(time(0)>start+10) break;
}
}
int main() {
thread t(process);
while(!t.timed_join(posix_time::seconds(1))) {
posix_time::ptime mst1 = posix_time::microsec_clock::local_time();
cout<<endl<<"attempting to lock"<<endl;
cout.flush();
unique_lock<mutex> lock(mut);
posix_time::ptime mst2 = posix_time::microsec_clock::local_time();
posix_time::time_duration msdiff = mst2 - mst1;
cout << std::endl<<"acquired lock in: "<<msdiff.total_milliseconds() << endl;
cout.flush();
}
}
如您所见,在最坏的情况下,显示线程等待424个锁释放周期,然后才开始捕获锁
很明显,我使用互斥体的方式是错误的,但解决这个问题的通常方法是什么?这并不是因为你使用互斥体的方式是错误的,只是线程并没有达到你期望的效果。操作系统决定何时运行哪个线程(这称为“调度”),代码中没有强制在循环结束时切换线程的内容;线程继续运行,并重新获得锁。要尝试的一件事是在释放锁后(在本例中,在循环顶部,重新锁定之前),添加对this_thread::yield()的调用;这将向调度程序建议它适合另一个线程运行。如果你真的想要紧密同步的交错,线程不会这样做;相反,编写一个更高级别的函数,逐个调用两个函数。如果更新线程没有其他事情要做,可以等待互斥锁变为可用 看看boost::condition_变量。你可以在这里读到 这里呢
如果更新线程进入睡眠将是一个问题——它是在许多GUI系统上的,而您没有指定使用哪一个——考虑从处理线程发布消息以更新线程。(同样,详细信息取决于您的平台。)该消息可能包含更新显示所需的信息,或者是“现在正是查看的好时机”的通知
如果您确实使用了条件代码,则处理线程可能会在发出条件信号后以及在重新获取锁以打开更新线程的大窗口之前屈服。您可能想看看,特别是方法
wait()
和notify_one()
或notify_all()
。方法wait()
将阻止当前线程,直到释放锁。方法notify\u one()
和notify\u all()
通知等待锁继续执行的一个或所有线程。在我看来,互斥锁的原则不是公平,而是正确性。互斥体本身无法控制调度程序。有一件事困扰着我,那就是为什么您选择创建两个线程,它们使用这种粗粒度的锁定。理论上,你是在并行运行两件事情,但事实上,你是在使它们相互依存/串联
Pete的想法似乎更好(一个函数运行这些draw&update),您仍然可以在每个内部函数中使用线程,而不必太担心争用和公平性
如果您真的希望两个线程并行运行,那么我可以给您一些提示:
- 使用原子的自旋锁,忘记互斥体
- 进入实施定义区域并设置线程优先级,或
- 使锁定更加细粒度
不幸的是,这两种方法都不是问题证明。我已经用Dale Wilson和FKaria提出的条件解决了问题,但我用的是相反的方向。因此,进程线程检查暂停标志,当设置它时,它等待一个条件,从而释放锁。显示线程控制暂停标志,它还通过通知条件来恢复进程线程。代码:(代码基本相同,我用
//new
标记了新行)
yield()。使用处理线程中的unique\u lock
构造之前的yield()
,在显示线程捕获锁之前,我仍然可以看到多达300次锁释放迭代。我真的不想要超紧交错,因为它只是一个显示,但如果它不等待300次反常的迭代,我将不胜感激:)Yuk。尝试调用sleep
;当一个线程睡眠时,任何合理的操作系统都会运行其他线程。我也尝试过,如果你睡眠0毫秒,那就好像睡眠不存在一样,否则你至少可以睡眠10毫秒,而这对于这种讨厌的事情来说简直太浪费了:/I我的意思是,这不像我在要求理论上的不可能,锁授予实现只需要将它提供给最早的候选对象。我已经尝试了条件变量
,但它不起作用notify_x
方法将其他线程置于“就绪”状态,但它们不强制唤醒。无论哪种方式,在等待锁之前,您首先需要锁,我的问题是无法获取锁。请注意,我的更新线程已经在等待互斥锁变为可用,但问题是即使在它可用之后,它也不会在很长时间内获取锁。如果GUI系统真的很重要,我的显示线程使用OpenGL做一些屏幕绘制。处理线程向更新线程发布消息真的没有帮助。显示线程在没有获得锁的情况下无法“查看”,这就是问题所在。除了常见的疑点:(条件变量、收益率)尝试一些线程安全容器…感谢您的建议,它们都有有用的案例,但我没有:spi
...................................................................................................
attempting to lock
....................................................................................................................................................................................................................................................................................................................................................................................................................................
acquired lock in: 4243
...................................................................................................
attempting to lock
........................................................................................................
acquired lock in: 1049
...................................................................................................
attempting to lock
........................................................................................................................
acquired lock in: 1211
....................................
#include <boost/thread.hpp>
#include <boost/thread/condition.hpp>
#include <iostream>
using namespace std;
using namespace boost;
mutex mut;
condition cond;
volatile bool shouldPause = false; //New
void process() {
double start = time(0);
while(1) {
unique_lock<mutex> lock(mut);
if(shouldPause) cond.wait(mut); //New
this_thread::sleep(posix_time::milliseconds(10));
std::cout<<".";
if(time(0)>start+10) break;
}
}
int main() {
thread t(process);
while(!t.timed_join(posix_time::seconds(1))) {
posix_time::ptime mst1 = posix_time::microsec_clock::local_time();
cout<<endl<<"attempting to lock"<<endl;
cout.flush();
shouldPause = true; // New
unique_lock<mutex> lock(mut);
posix_time::ptime mst2 = posix_time::microsec_clock::local_time();
posix_time::time_duration msdiff = mst2 - mst1;
cout << std::endl<<"acquired lock in: "<<msdiff.total_milliseconds() << endl;
cout.flush();
shouldPause = false; // New
cond.notify_all(); // New
}
}
...................................................................................................
attempting to lock
.
acquired lock in: 9
...................................................................................................
attempting to lock
.
acquired lock in: 8
...................................................................................................
attempting to lock
.
acquired lock in: 9
...................................................................................................
attempting to lock
.
acquired lock in: 8
...................................................................................................
attempting to lock
.
acquired lock in: 9
...................................................................................................
attempting to lock
.
acquired lock in: 9
...................................................................................................
attempting to lock
.
acquired lock in: 9
...................................................................................................
attempting to lock
.
acquired lock in: 9
...................................................................................................
attempting to lock
.
acquired lock in: 8
...................................................................................................
attempting to lock
.
acquired lock in: 9
..........................