【问题标题】:c++ Handling multiple threads in a main threadc++ 在一个主线程中处理多个线程
【发布时间】:2017-03-07 20:58:09
【问题描述】:

我对多线程有点陌生,如果这些问题太琐碎,请见谅。

我的应用程序需要在一个线程中创建多个线程并从每个线程执行操作。

例如,我有一组文件要读取,比如 50 个,我创建了一个线程来使用 CreateThread() 函数读取这些文件。

现在这个主线程创建了 4 个线程来访问文件。第一个线程被赋予文件 1,第二个文件 2 等等。

在第一个线程完成读取文件1并给主线程所需的数据后,主线程需要调用文件5并从中获取数据。在读取所有 50 个文件之前,所有其他线程也是如此。

之后,每个线程都被销毁,最后我的主线程也被销毁了。

我面临的问题是:

1) 文件读取后如何停止线程退出?

2) 如何用其他文件名再次调用线程?

3) 我的子线程如何向主线程提供信息?

4) 一个线程读完文件并给主线程返回一个数据后,主线程如何知道是哪个线程提供了数据?

谢谢

【问题讨论】:

    标签: c++ multithreading visual-studio-2005


    【解决方案1】:

    这是多线程编程中很常见的问题。您可以将其视为生产者-消费者问题:主线程“生产”任务,这些任务被工作线程“消费”(例如 http://www.mario-konrad.ch/blog/programming/multithread/tutorial-06.html)。您可能还想了解“线程池”。

    我强烈建议阅读 boost 的同步 (http://www.boost.org/doc/libs/1_50_0/doc/html/thread.html) 并使用 boost 的线程功能,因为它独立于平台且易于使用。

    为了更具体地解决您的问题:您应该创建一个包含要完成的操作的队列(通常它对于所有工作线程来说都是同一个队列。如果您真的想确保线程 1 正在执行任务 1、5、9 .. . 您可能希望每个工作线程有一个队列)。对该队列的访问必须通过mutex 同步,当新数据添加到互斥体时,可以通过condition_variables 通知等待线程。

    1.) 不要退出线程函数,而是等到某个条件被触发,然后使用while ([exit condition not true]) 循环重新启动

    2.) 见 1.

    3.) 通过任何变量都可以访问并由mutex 保护(例如结果队列)

    4.) 通过将此信息作为写入结果队列的结果添加。

    另一个建议:总是很难正确处理多线程。所以尽量小心并编写测试来检测死锁和竞争条件。

    【讨论】:

      【解决方案2】:

      这类问题的典型解决方案是使用线程池和队列。主线程将所有文件/文件名推送到一个队列,然后启动一个线程池,即不同的线程,其中每个线程从队列中取出一个项目并处理它。当一个项目被处理时,它会继续下一个(如果到那时队列还不是空的)。当队列为空并且所有线程都退出时,主线程知道所有内容都已处理。

      所以,1) 和 2) 有点冲突:您不会停止线程并再次调用它,只要它在队列中找到项目,它就会一直运行。 对于 3),您可以再次使用线程放入信息的队列,并从中读取主线程。对于 4),您可以给每个线程一个 id 并将其与数据放在一起。但是通常主线程不需要知道哪个线程准确地处理了数据。

      一些非常基本的伪代码给你一个想法,省略了线程安全锁定:

      //main
      for( all filenames )
        queue.push_back( filename );
      
      //start some thread
      threadPool.StartThreads( 4, CreateThread( queue ) );
      
      //wait for threads to end
      threadPool.Join();
      
      //thread
      class Thread
      {
      public:
        Thread( queue q ) : q( q ) {}
      
        void Start();
      
        bool Join();
      
        void ThreadFun()
        {
          auto nextQueueItem = q.pop_back();
          if( !nextQueuItem )
            return; //q empty
          ProcessItem( nextQueueItem );
        }
      }
      

      【讨论】:

      • queue 还是std::queue?那么您的示例缺少互斥锁或其他锁定机制,对吗?
      【解决方案3】:

      无论您是否使用线程池来执行同步文件读取,它都归结为必须序列化运行的函数链或函数组。所以让我们假设,您找到了一种并行执行函数的方法(无论是每个函数启动一个线程还是使用线程池),等待前 4 个文件读取,您可以使用队列,其中读取线程将结果推入,第五个函数现在从队列中拉出 4 个结果(队列为空时阻塞)并处理。如果函数之间存在更多的依赖关系,您可以在它们之间添加更多队列。草图:

      void read_file( const std::string& name, queue& q )
      {
          file_content f= .... // read file
          q.push( f )
      }
      
      void process4files( queue& q )
      {
          std::vector< file_content > result;
          for ( int i = 0; i != 4; ++i )
              result.push_back( q.pop() ); 
      
          // now 4 files are read ...
          assert( result.size() == 4u );
      }
      
      queue       q;
      thread t1( &read_file, "file1", q );
      thread t2( &read_file, "file2", q );
      thread t3( &read_file, "file3", q );
      thread t4( &read_file, "file4", q );
      thread t5( &process4files, q );
      
      t5.join();
      

      希望你能明白。

      托尔斯滕

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-27
        相关资源
        最近更新 更多