代码之家  ›  专栏  ›  技术社区  ›  enobayram

一旦锁定可用,立即获取锁定

  •  5
  • enobayram  · 技术社区  · 11 年前

    我有两个线程试图锁定相同的线程 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个锁释放周期,然后才能捕获锁。

    很明显,我使用互斥锁的方式不对,但解决这个问题的常用方法是什么?

    5 回复  |  直到 11 年前
        1
  •  4
  •   Pete Becker    11 年前

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

        2
  •  1
  •   Community Michael Schmitz    7 年前

    如果更新线程没有其他事情要做,它可以等待互斥对象变为可用。

    查看boost::condition_variable。你可以在这里阅读 http://www.boost.org/doc/libs/1_53_0/doc/html/thread/synchronization.html 还有这里 Using boost condition variables

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

    如果您确实使用了条件代码,那么处理线程可能会在发出条件信号后,在重新获取锁以为更新线程打开一个大窗口之前屈服。

        3
  •  1
  •   FKaria    11 年前

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

        4
  •  1
  •   Red XIII    11 年前

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

    Pete的想法似乎要好得多(一个函数运行这些draw&update),并且您仍然可以在每个内部函数中使用线程,而不必太担心争用和公平性。

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

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

    不幸的是,这两种方法都不能解决问题。

        5
  •  0
  •   enobayram    11 年前

    正如Dale Wilson和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
    ..........................