4

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

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

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

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

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

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

我面临的问题是:

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

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

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

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

谢谢

4

3 回答 3

4

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

我强烈建议阅读 boost 的 Synchronization ( 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.) 通过将此信息作为写入结果队列的结果添加。

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

于 2012-07-20T10:00:17.180 回答
0

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

因此,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 );
  }
}
于 2012-07-20T10:01:42.740 回答
0

无论您是否使用线程池来执行同步文件读取,它都归结为必须序列化运行的函数链或函数组。所以让我们假设,您找到了一种并行执行函数的方法(无论是每个函数启动一个线程还是使用线程池),等待前 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();

我希望你能明白。

托尔斯滕

于 2012-07-20T11:07:33.730 回答