【问题标题】:Mutex-managed threads processed in "chunks" instead of interlacing互斥管理的线程以“块”而不是交错处理
【发布时间】:2014-11-29 17:50:51
【问题描述】:

我目前正在尝试使用名为mutexCOM 的共享互斥体获得两个boost::threads,以在CPU 上获得相等的处理时间。就目前而言,两个线程都设置为无限运行。一个线程(主线程)简单地打印出“测试!”而另一个线程,运行Navigation::begin() 函数,打印“-----shared function-----”,等待一秒钟,然后打印“-----Shared function will now end...-- ——”。等待旨在模拟将替换此存根的函数所需的大量处理。无限循环的每次迭代都在循环内通过mutexCOM 上的作用域锁进行。预期的输出应该类似于以下无穷大:

testing!
-----shared function-----
----Shared function will now end...-----
testing!
-----shared function-----
----Shared function will now end...-----

不幸的是,我所做的某件事导致输出变为:

`

似乎迭代被组合在一起,而不是像我预期的那样交错。如果有人能解释这里发生了什么,我将不胜感激,因为我对使用互斥锁进行线程管理的理解似乎可以做一些工作。

我唯一的理论是,我认为 boost 处理队列以锁定互斥锁的假设是错误的,并且我需要以某种方式创建自己的队列以给予线程公平访问以避免饥饿。但是,我对此表示怀疑,因为它基本上会使互斥锁的意义变得毫无意义,因为我仍然需要自己处理所有管理。那为什么不直接使用信号量呢?

我的代码如下。仅包含相关代码,因此不必担心缺少类结构。假设所有标头都已正确包含,并且 SharedMutex.h 包含在两个类中:

SharedMutex.h -

#ifndef SHARED_MUTEX_
#define SHARED_MUTEX_
#include <boost/thread/mutex.hpp>
extern boost::mutex mutexCOM;
#endif

导航.cpp -

Navigation::begin() {
    boost::mutex::scoped_lock lock(mutexCOM);
    cout<< "-----shared function-----" << endl;
    sleep(1);
    cout<< "----Shared function will now end...-----" << endl;
}

mainclass.cpp -

void mainclass::run() {
    this->runNav();
    while(1) {
        boost::mutex::scoped_lock lock(mutexCOM);
        cout << "testing!" << endl;
    }
}
void mainclass::runNav() {
//this->nav is an instance of Navigation within mainclass
boost::thread navThread(boost::bind(&Navigation::begin, *(this->nav)));
//this->navPtr is a pointer to the boost::thread for later management
this->navPtr=&navThread;
}

【问题讨论】:

  • 无法保证控件只会从一个线程传递到另一个线程。我会引入条件等待您的 navThread 并让主线程发出信号它已完成。
  • 如何在线程之间发出信号?那会通过互斥锁来完成吗?此外,我认为互斥体包含一个 FIFO 队列来处理这种确切的场景
  • 信号量是首选的方法
  • 另外值得注意的是,这可能只是一个时间问题,也许输出“testing1”10 次左右比 boost 启动和运行 Nav 线程的速度更快?
  • StackOverflow 派上用场了! stackoverflow.com/questions/16907072/…

标签: c++ multithreading boost mutex boost-thread


【解决方案1】:

这是错误的:

    // this->navPtr is a pointer to the boost::thread for later management
    this->navPtr = &navThread;

您正在那里获取局部变量的地址。如果您稍后使用navPtr,那就是未定义的行为。相反,只需将线程存储在成员中:请参见下面的示例。

但是,我对此表示怀疑,因为它基本上会使互斥锁的意义变得毫无意义,因为我仍然需要自己处理所有管理

确实如此。如果您想要任务排队,请编写它。互斥锁不是为了那个。顾名思义,互斥锁只是为了互斥,两个代码块(临界区)做的基本保证不同时运行。

它不保证其他任何东西。

线程饥饿确实是问题所在,这可以通过在某些时候引入 yield/sleeps 来证明:

Live On Coliru

#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/scoped_ptr.hpp>
#include <iostream>

static boost::mutex mutexCOM;

struct Navigation {
    void begin() {
        size_t count = 0;
        while(++count< 10) {
            {
                boost::mutex::scoped_lock lock(mutexCOM);
                std::cout << "-----shared function-----" << std::endl;
                boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
                std::cout << "----Shared function will now end...-----" << std::endl;
            }
            boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); // or boost::this_thread::yield e.g.
        }
        std::cout << "Navigation::begin() completed\n";
    }
};

struct mainclass {
    void run() {
        size_t count = 0;
        this->runNav();
        while (++count < (1ull<<20))
        {
            {
                boost::mutex::scoped_lock lock(mutexCOM);
                std::cout << "testing!" << std::endl;
            }

            boost::this_thread::yield();
        }
        std::cout << "mainclass::run() completed\n";
    }

    ~mainclass() {
        if (navThread.joinable())
        {
            std::cout << "Waiting for Navigation to end...\n";
            navThread.join();
        }
    }
  private:
    void runNav() {
        navThread = boost::thread(boost::bind(&Navigation::begin, *(this->nav)));
    }

    boost::scoped_ptr<Navigation> nav { new Navigation };
    boost::thread navThread;
};

int main() {
    mainclass instance;
    instance.run();
}

哪个打印:./a.out | uniq -c

      1 testing!
      1 -----shared function-----
      1 ----Shared function will now end...-----
   9726 testing!
      1 -----shared function-----
      1 ----Shared function will now end...-----
   5501 testing!
      1 -----shared function-----
      1 ----Shared function will now end...-----
   5197 testing!
      1 -----shared function-----
      1 ----Shared function will now end...-----
   5316 testing!
      1 -----shared function-----
      1 ----Shared function will now end...-----
   5913 testing!
      1 -----shared function-----
      1 ----Shared function will now end...-----
   5515 testing!
      1 -----shared function-----
      1 ----Shared function will now end...-----
   5639 testing!
      1 -----shared function-----
      1 ----Shared function will now end...-----
   5352 testing!
      1 -----shared function-----
      1 ----Shared function will now end...-----
   5162 testing!
      1 Navigation::begin() completed
 995253 testing!
      1 mainclass::run() completed
      1 Waiting for Navigation to end...

【讨论】:

  • 啊,看来这是我的错误信息。感谢您不厌其烦地写出那个例子。
  • @SwarthyMantooth 干杯!我也刚刚修复了格式错误的输出:/
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
  • 2012-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-23
  • 2021-04-24
相关资源
最近更新 更多