c ++处理主线程中的多个线程

时间:2012-07-20 09:45:13

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

我对多线程有点新意,所以请原谅我,如果这些问题太微不足道了。

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

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

现在这个主线程创建了4个线程来访问该文件。第一个线程是文件1,第二个文件是2,依此类推。

在第一个线程完成读取文件1并向主线程提供所需数据后,主线程需要使用文件5调用它并从中获取数据。在读取所有50个文件之前,所有其他线程都类似。

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

我面临的问题是:

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

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

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

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

由于

3 个答案:

答案 0 :(得分:4)

这是多线程编程中非常常见的问题。您可以将此视为生产者 - 消费者问题:主线程“生成”由工作线程“消耗”的任务(例如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。)将此信息作为结果写入结果队列。

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

答案 1 :(得分: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 );
  }
}

答案 2 :(得分: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();

我希望你明白这一点。

的Torsten