2015-02-07 33 views
4

我有一個std::thread功能正在調用fopen一個大文件加載到一個數組:殺的std ::線程同時讀取大文件

std::thread loader(loadfile, fname, fbuffer, fsize); 
loader.detach(); 

void loadfile(char *fname, char *fbuffer, long fsize) 
{ 
    FILE *fp = fopen(fname, "rb"); 
    fread(fbuffer, 1, fsize, fp); 
    flose(fp); 
} 

這是通過所謂的在某個時候,我的程序中的某些內容想要停止閱讀該文件並要求另一個文件。問題是,當我刪除fbuffer指針時,loader線程仍在繼續,並且我得到一個導致異常的競爭條件。

我該如何殺死那個線程?我的想法是,以檢查fbuffer是否存在等,也許分割一小塊一小塊的fread

void loadfile(char *fname, char *fbuffer, long fsize) 
{ 
    FILE *fp = fopen(fname, "rb"); 
    long ch = 0; 
    while (ch += 256 < fsize) 
    { 
    if (fbuffer == NULL) return; 
    fread(fbuffer + ch, 1, 256, fp); 
    } 
    fclose(fp); 
} 

這是否會降低文件的閱讀?你有更好的主意嗎?

+0

讓線程運行,畢竟你不必使用結果。 – 2015-02-07 17:24:03

+0

你不能殺死一個分離的花紋:http://en.cppreference.com/w/cpp/thread/thread/detach – 2015-02-07 17:25:25

+0

@UlrichEckhardt如果我在線程運行時刪除'fbuffer',程序就會崩潰。 – 2015-02-07 17:37:08

回答

5

你應該避免不惜一切代價殺死一個線程。這樣做會導致惡意事件發生,例如永久鎖定狀態下的資源。

線程必須考慮到一個標誌的參考,這些都可以從其他地方設置的值,來告訴線程自願退出。

不能使用緩衝區用於此目的;如果一個線程刪除緩衝區的內存而另一個線程正在寫入該緩衝區,則會發生非常惡劣的事情。 (內存損壞。)所以,傳遞一個布爾標誌的引用。

當然,爲了讓線程能夠定期檢查標誌,它必須有小塊工作要做,因此將您的fread s分成小塊是個不錯的主意。

256字節可能是有點太小了,雖然;肯定使用4k或更多,甚至可能是64k。

0

殺死線程通常不是要走的路 - 做這個may lead to leaked resources, critical sections you cannot exitinconsistent program state.

你的點子幾乎是抽查,但你需要一種方法來信號線來完成。您可以在線程和代碼的其餘部分之間使用布爾值,在每次讀取之後線程都會讀取它們,一旦設置,停止讀入緩衝區就會清理文件句柄並乾淨地退出。

在另一個說明中,處理自己擁有語義的指針刪除在大多數時候都是在現代C++中不受歡迎的 - 除非你有一個非常好的理由,否則我建議使用stl fstream和string類。

0

您需要正確的線程同步。關於資源泄漏的意見以及@Mike Nakis關於通過設置一個布爾值來自動退出線程的建議是幾乎正確(好吧,它們是正確,但不完整)。你需要走得更遠。

您必須確保不僅加載程序線程自行退出,還必須確保在刪除正在寫入的緩衝區之前已退出加載程序線程。或者,至少,您必須確保它在刪除後不會以任何方式觸及該緩衝區。檢查null-ness指針不起作用有兩個原因。首先,它不起作用,因爲您正在查看原始指針的副本(您將不得不使用指針指針或引用)。其次,更重要的是,即使支票工作,在if聲明與fread之間也存在爭用條件。換句話說,無法保證在fread正在訪問緩衝區時沒有釋放緩衝區(無論您製作的塊有多小)。

最起碼,你需要兩個布爾標誌,但最好使用等適當的同步原語,例如條件變量來通知主線程(所以你不必旋轉等待加載器退出,但可以阻止)。

正確的操作方法是:

  1. 通知裝載機螺紋
  2. 等待裝載機線程信號Me(上COND VAR塊)
  3. 裝載機線程拿起通知,設定條件變量之後永不接觸緩衝區,然後退出
  4. 恢復(刪除緩衝區,分配新緩衝區等)

如果您不堅持拆卸裝載程序線程,您可以簡單地在join之後告訴它退出(因此您不需要cond變量)。