我对多线程有点新意,所以请原谅我,如果这些问题太微不足道了。
我的应用程序需要在线程中创建多个线程并从每个线程执行操作。
例如,我有一组要读取的文件,比如50,我创建了一个线程来使用CreateThread()函数读取这些文件。
现在这个主线程创建了4个线程来访问该文件。第一个线程是文件1,第二个文件是2,依此类推。
在第一个线程完成读取文件1并向主线程提供所需数据后,主线程需要使用文件5调用它并从中获取数据。在读取所有50个文件之前,所有其他线程都类似。
之后,每个线程都被销毁,最后我的主线程被销毁。
我面临的问题是:
1)如何在文件读取后停止线程退出?
2)如何用其他文件名再次调用线程?
3)我的子线程如何向主线程提供信息?
4)线程完成读取文件并返回主线程数据后,主线程如何知道哪个线程提供了数据?
由于
答案 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