2012-07-20 77 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