C ++ - 有关多线程的问题

时间:2014-01-10 08:16:28

标签: c++ multithreading algorithm

我无法理解多线程的一些概念。我知道基本原则,但是在理解核心发送和使用各个线程时遇到了问题。

我知道拥有多个线程允许代码并行运行。我认为这将是我的归档提取程序的一个很好的补充,它可以使用多个核心解压缩块。它解压缩for循环中的所有文件,我希望每个可用的核心都能在文件上工作。

以下是我的问题:

  1. 我是否需要查询甚至考虑计算机上的核心数量或线程运行时,它们会自动发送到免费核心?

  2. 任何人都可以给我看一个使用线程的for循环的例子。比如在每次循环迭代中,它会使用不同的线程调用函数。我读到有活跃的线程的理想数量是核心数。我如何知道核心何时是空闲的,还是应该检查它是否已加入主线程,并在必须保持一定数量的线程运行时创建新线程。

  3. 我是在过度复杂的事情还是我的问题表明我没有理解这些概念?

4 个答案:

答案 0 :(得分:3)

如果您正在解压缩文件,那么您可能需要一个有限数量的线程而不是每个文件一个线程。否则,如果你正在处理1000个文件,你将创建1000个线程,这将无法有效地使用cpu。

正如您所提到的,一种方法是创建与核心一样多的线程,这是一种合理的方法,因为解压缩是合理的cpu绑定,因此您创建的任何线程都将在大多数情况下处于活动状态他们的时间片。如果您的IO问题受到限制,那么您的线程将花费大量时间等待IO完成,因此您可以在界限范围内旋转更多线程,而不是内核。

对于您的应用程序,我可能会考虑为每个核心启动一个线程,并让每个线程一次处理一个文件。这将有助于保持算法简单。如果您有多个线程处理一个文件,那么您必须在它们之间进行同步,以确保它们处理的块被写入未压缩文件中的正确位置,这将导致不必要的麻烦。

C ++ 11包含一个thread library,您可以使用它来简化线程的使用。

答案 1 :(得分:2)

  1. 不,您可以使用保持透明的API,例如Linux(pthread库)上的POSIX线程。

  2. 这个答案可能取决于您使用的API,尽管许多API共享线程基础知识,如互斥锁。但是,这是一个pthreads示例(因为这是我所知道的唯一的C / C ++线程API)。

    #include <stdio.h>
    #include <stdlib.h>        
    #include <pthread.h>
    // Whatever other headers you need for your code.
    
    #define MAX_NUM_THREADS 12
    
    // Each thread will run this function.
    void *worker( void *arg )
    {
        // Do stuff here and it will be 'in parallel'.
    
        // Note: Threads can read from the same location concurrently
        // without issue, but writing to any shared resource that has not been
        // locked with, for example, a mutex, can cause pernicious bugs.
    
        // Call this when you're done.
        pthread_exit( NULL );
    }
    
    int main()
    {
        // Each is a handle for one thread, with 12 in total.
        pthread_t myThreads[MAX_NUM_THREADS];
    
        // Create the worker threads.
        for(unsigned long i = 0; i < numThreads; i++)
        {
            // NULL thread attributes struct.
            // This initializes the threads with the default PTHREAD_CREATE_JOINABLE
            // attribute; we know a thread is finished when it joins, see below.
            pthread_create(&myThreads[i], NULL, worker, (void *)i);
        }
    
        void *status;
        // Wait for the threads to finish.
        for(unsigned int i = 0; i < numThreads; i++)
        {
            pthread_join(myThreads[i], &status);
        }
    
        // That's all, folks.
        pthread_exit(NULL);
    }
    
  3. 没有太多细节,对于使用pthreads的简单线程应用程序来说,这是一个非常基本的框架。

    关于将此问题应用于您的计划的最佳方式的问题:

    我建议每个文件使用一个帖子,使用Threadpool Pattern,这就是原因:

    每个文件的单个帖子要简单得多,因为没有共享,因此没有同步。您可以将worker功能更改为decompressFile功能,每次调用pthread_create时都会传递文件名。基本上就是这样。你的线程池模式就在这里。

    每个文件多个线程表示同步,这意味着复杂性,因为您必须管理对共享资源的访问。为了加快算法速度,您必须隔离可以并行运行的部分算法。但是,我实际上希望此方法运行较慢

    想象一下,线程A打开文件A,线程B打开文件B,但文件A和文件B位于磁盘的完全不同的扇区中。作为线程A以及线程B之间的OS的调度算法开关,硬盘驱动器具有旋转疯狂跟上,使得CPU(因此你的程序)等。

答案 2 :(得分:1)

由于您似乎是新的线程/并行,并且您只想从多个处理器/内核中获得更多性能,我建议您寻找处理线程的库,并允许您在不进入线程管理的情况下启用并行性,工作分配等。

听起来您现在需要的是并行循环执行。现在有很多C ++库可以为您轻松完成这项任务,例如:英特尔的TBB,微软的PPL,AMD的博尔特,Quallcomm的MARE等等。您可以比较许可条款,支持的平台,功能并做出最适合您需求的选择。

更具体地回答您的问题:

1)通常,您不需要知道/考虑处理器或核心的数量。选择一个库,从您和您的程序中抽象出这个细节。另一方面,如果您看到使用默认设置CPU未被充分利用(例如,由于大量的I / O操作),您可能会发现要求更多线程是有用的,例如将默认值乘以某个因子。

2)for循环的草图与tbb::parallel_for和C ++ 11 lambda函数并行:

#include <tbb/tbb.h>
void ParallelFoo( std::vector<MyDataType>& v ) {
    tbb::parallel_for( size_t(0), v.size(), [&](int i){
        Foo( v[i] );
    } );
}

请注意,不保证每个迭代都由单独的线程执行;但你实际上不应该担心这些细节;所有你需要的是可用内核忙于有用的工作。

免责声明:我是Intel's TBB图书馆的开发者。

答案 3 :(得分:0)

如果你在Windows上,你可以看看线程池,可以在这里找到一个很好的描述:http://msdn.microsoft.com/en-us/magazine/cc163327.aspx。该工具的一个有趣特性是它承诺为您管理线程。它还根据需求和可用内核选择最佳线程数。