5

我有两个线程试图锁定相同的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();
        }

}

编译:g++ mutextest.cpp -lboost_thread -pthread

当我运行可执行文件时,示例输出如下所示:

...................................................................................................
attempting to lock
....................................................................................................................................................................................................................................................................................................................................................................................................................................
acquired lock in: 4243
...................................................................................................
attempting to lock
........................................................................................................
acquired lock in: 1049
...................................................................................................
attempting to lock
........................................................................................................................
acquired lock in: 1211
....................................

如您所见,在最坏的情况下,显示线程会等待 424 个锁释放周期,然后才开始捕获锁。

我显然以错误的方式使用互斥锁,但解决这个问题的常用方法是什么?

4

5 回答 5

4

并不是你使用错了互斥锁,只是线程没有达到你期望的效果。操作系统决定何时运行哪个线程(这称为“调度”),并且代码中没有任何内容会在循环结束时强制线程切换;线程继续运行,并重新获得锁。要尝试的一件事是this_thread::yield()在释放锁之后添加一个调用(在这种情况下,在循环的顶部,在重新锁定之前);这将向调度程序建议它适合另一个线程运行。如果你真的想要紧密同步的交错,线程不会这样做;相反,编写一个更高级别的函数,一个接一个地调用您的两个函数。

于 2013-04-05T15:32:35.953 回答
1

如果更新线程无事可做,它可以等待互斥体可用。

查看 boost::condition_variable。你可以在这里阅读 http://www.boost.org/doc/libs/1_53_0/doc/html/thread/synchronization.html 和这里 使用升压条件变量

如果让更新线程进入睡眠状态会是一个问题——它在许多 GUI 系统上并且你没有指定你正在使用哪一个——考虑将消息从处理线程发布到更新线程。(同样,详细信息取决于您的平台。)该消息可能包含更新显示所需的信息,或者是“现在是查看的好时机”的通知。

如果您确实使用条件代码,则处理线程可能应该在发出条件信号之后并在重新获取锁以为更新线程打开一个大窗口之前让步。

于 2013-04-05T15:36:52.537 回答
1

您可能想看看boost::condition_variable,特别是方法wait()notify_one()or notify_all()。该方法wait()将阻塞当前线程,直到锁被释放。方法notify_one()notify_all()通知一个或所有等待锁继续执行的线程。

于 2013-04-05T15:42:49.010 回答
1

在我看来,互斥锁的原则不是公平,而是正确。互斥锁本身无法控制调度程序。困扰我的一件事是您选择创建 2 个使用这种粗粒度锁定的线程的原因。从理论上讲,您正在并行运行两件事,但实际上您正在使它们相互依赖/串行。

Pete 的想法似乎更好(一个函数运行这些绘制和更新),您仍然可以在每个内部函数中使用线程,而不必担心争用和公平性。

如果您真的希望让两个线程并行运行,那么我可以给您一些提示:

  • 使用原子的自旋锁并忘记互斥锁,
  • 进入实现定义的区域并设置线程优先级,或者
  • 使锁定更加细粒度。

不幸的是,这些都不是问题证明。

于 2013-04-05T17:17:02.330 回答
0

正如 Dale Wilson an FKaria 所建议的那样,我已经使用条件解决了这个问题,但我已经在相反的方向使用它。因此,进程线程检查暂停标志,当它被设置时,它等待一个条件,从而释放锁。显示线程控制暂停标志,它还通过条件通知它来恢复进程线程。代码:(代码基本相同,我用 标记了新行//New

#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
..........................
于 2013-04-06T06:12:13.817 回答