提升串行运行的线程,而不是并行运行

Posted

技术标签:

【中文标题】提升串行运行的线程,而不是并行运行【英文标题】:Boost threads running serially, not in parallel 【发布时间】:2011-03-03 10:30:16 【问题描述】:

我是 C++ 中多线程的完全新手,并决定从 Boost 库开始。另外,我在 Vista 上使用 Intel 的 C++ 编译器(来自 Parallel Studio 2011)和 VS2010。

我正在编写一个遗传算法,并想利用多线程的好处:我想为种群中的每个个体(对象)创建一个线程,以便他们计算它们的适应度(繁重的操作)并行,以减少总执行时间。

据我了解,每当我启动子线程时,它都会“在后台”工作,而父线程会继续执行下一条指令,对吗?所以,我想创建并启动我需要的所有子线程(在for 循环中),然后等待它们完成(在另一个for 循环中调用每个线程的join()),然后再继续。

我面临的问题是,在新创建的线程完成工作之前,第一个循环不会继续到下一次迭代。然后,第二个循环就好了,因为在循环被命中时所有线程都已经加入了。

这里是(我认为是)相关代码 sn-ps。如果您还有其他需要知道的,请告诉我。

class Poblacion 
    // Constructors, destructor and other members
    // ...
    list<Individuo> _individuos;
    void generaInicial()  // This method sets up the initial population.
        int i;
        // First loop
        for(i = 0; i < _tamano_total; i++) 
            Individuo nuevo(true);
            nuevo.Start(); // Create and launch new thread
            _individuos.push_back(nuevo);
        

        // Second loop
        list<Individuo>::iterator it;
        for(it = _individuos.begin(); it != _individuos.end(); it++) 
            it->Join();
        

        _individuos.sort();
    
;

还有,线程对象Individuo

class Individuo 
    private:
        // Other private members
        // ...
        boost::thread _hilo;

    public:
        // Other public members
        // ...
        void Start() 
            _hilo = boost::thread(&Individuo::Run, this);
        
        void Run() 
            // These methods operate with/on each instance's own attributes,
            // so they *can't* be static
            generaHoc();
            calculaAptitud();
            borraArchivos();
        
        void Join() 
            if(_hilo.joinable()) _hilo.join();
        
;

谢谢! :D

【问题讨论】:

用 Boost.threads 做这样的事情很有趣,但 OpenMP 会更容易 @CharlesB 我认为对于这种特殊情况,问题已经解决,但我会研究 OpenMP。谢谢你的建议。 【参考方案1】:

如果那是你的真实代码,那么你就有问题了。

    for(i = 0; i < _tamano_total; i++) 
        Individuo nuevo(true);
        nuevo.Start(); // Create and launch new thread
        _individuos.push_back(nuevo);
    

    void Start() 
        _hilo = boost::thread(&Individuo::Run, this);
    

此代码在堆栈上创建一个新的Individuo 对象,然后启动一个运行的线程,将该堆栈对象的thispointer 传递给新线程。然后它复制该对象到list,并立即销毁堆栈对象,在新线程中留下一个悬空指针。这会给你带来不确定的行为。

由于list 在插入对象后从不移动内存中的对象,因此您可以在插入列表后启动线程:

    for(i = 0; i < _tamano_total; i++) 
        _individuos.push_back(Individuo(true)); // add new entry to list
        _individuos.back().Start(); // start a thread for that entry
    

【讨论】:

是的!这正是问题所在。我确信它与 list.push_back() 复制对象有关(因为我不得不重载复制 ctor 但无法真正抓住问题 - 我尝试使用指向线程而不是线程但它只出现了一些奇怪的引用计数错误)。但我离题了...非常感谢!

以上是关于提升串行运行的线程,而不是并行运行的主要内容,如果未能解决你的问题,请参考以下文章

Tomcat JSP 似乎是串行运行(而不是并行运行)——我错过了啥?

多核并行编程技术

线程并行执行转为串行的法宝 join()

并行,并发,串行,同步,异步,阻塞,非阻塞,同步阻塞,同步非阻塞,异步阻塞,异步非阻塞

尽管并行编译,Mex 文件仍串行执行

延迟线程启动 - 通知所有未唤醒所有线程