2012-07-20 76 views
3

我对多线程有点新,所以请原谅我,如果这些问题太微不足道了。C++处理主线程中的多线程

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

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

现在这个主线程创建4个线程来访问文件。第一个线程给出文件1,第二个文件2等等。

第一个线程完成读取文件1并给主线程所需的数据后,主线程需要用文件5调用它并从中获取数据。所有其他线程的情况类似,直到读取所有50个文件。

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

我现在面临的问题是:

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

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

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

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

谢谢

回答

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.)通过添加此信息作为写入结果队列的结果。

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

0

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

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

一些非常基本的伪代码,给你一个想法,锁定为threadsafety省略:

//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); 
    } 
} 
+0

是'队列'的'std :: queue'吗?那么你的例子就是缺少互斥或其他锁定机制,对吧? – Philipp 2012-07-23 06:52:08

+0

这就是为什么它说'锁定螺纹省略':] – stijn 2012-07-23 07:27:34

+0

哎呀,对不起:-) – Philipp 2012-07-23 07:58:35

0

无论是使用线程池或不执行你的synchronies文件读取,把它归结为功能或链条必须运行序列化的函数组。因此,让我们假设,您可以找到一种并行执行函数的方法(无论是为每个函数启动一个线程还是通过使用线程池),等待前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