對多執行緒完全陌生。
我正在撰寫一個程式,該程式將物件向量和用于專用執行緒數的整數作為輸入。物件的性質并不重要,只是每個物件都有幾個成員,它們是大型文本檔案的檔案路徑。這是一個簡化版本:
// Not very important. Reads file, writes new version omitting
// some lines
void proc_file(OBJ obj) {
std::string inFileStr(obj.get_path().c_str());
std::string outFileStr(std::string(obj.get_path().replace_extension("new.txt").c_str()));
std::ifstream inFile(inFileStr);
std::ofstream outFile(outFileStr);
std::string currLine;
while (getline(inFile, currLine)) {
if (currLine.size() == 1 ||
currLine.compare(currLine.length()-5, 5, "thing") != 0) {
outFile << currLine << '\n';
}
else {
for (int i = 0; i < 3; i ) {
getline(inFile, currLine);
}
}
}
inFile.close();
outFile.close();
}
// Processes n file concurrently, working way through
// all OBJ in objs
void multi_file_proc(std::vector<OBJ> objs, int n) {
std::vector<std::thread> procVec;
for (int i = 0; i < objs.size(); i ) {
/*
Ensure that n files are always being processed.
Upon completion of one, initiate another, until
all OBJ in objs have had their text files changed.
*/
}
}
我想遍歷每個 OBJ 并同時寫入其文本檔案的更改版本,同時檔案讀/寫的限制是執行緒值(n)。最終,必須更改所有物件的文本檔案,但要始終處理n 個檔案,以最大限度地提高并發效率。
注意執行緒向量procVec。我最初通過管理一個執行緒向量來解決這個問題,并為 procVec 中的每個執行緒處理一個檔案。從我的閱讀來看,管理這些任務的向量似乎是合乎邏輯的。但是,我如何始終確保在所有檔案都被處理之前打開 n 個檔案,而不用打開的執行緒退出?
編輯:抱歉,我的目的不是要求別人為我撰寫代碼。如果方法一開始就不好,我只是不希望我的方法偏向任何人的答案。
這些是我嘗試過的一些事情(此代碼將進入我函式中的塊注釋):
1.第一種方法。想法是添加到procVec直到達到執行緒限制n,然后加入,在完成后從向量的前面洗掉一個行程。這是幾個類似迭代的總結,但都沒有奏效:
if (i >= n) {
procVec.front().join();
procVec.erase(procVec.begin());
}
procVec.push_back(std::thread(proc_file, sra[i]));
這方面的問題:
- 錯誤地假設向量的前面總是先完成
- (可能?)在 first 被擦除后使 procVec中的所有迭代器無效
2.使用互斥體,我嘗試撰寫一個 lambda 函式,其中執行緒將在其完成后被洗掉。這是我目前的做法。不確定為什么它不起作用,或者它是否適合我的需要:
// remThread() and lamb() defined above main function, **procVec** and **threadMutex**
//are global variables
void remThread(std::thread::id id) {
std::lock_guard<std::mutex lock(threadMutex);
auto iter = std::find_if(procVec.begin(), procVec.end(), [=](std::thread &t)
{return (t.get_id() == id); });
if (iter != procVec.end()) {
iter->join();
procVec.erase(iter);
}
}
void lamb(SRA sra, std::thread::id id) {
proc_file(sra);
remThread(id);
}
// This is the code contained in the main for loop. called lambda to process file
// and then remove thread
std::lock_guard<std::mutex> lock(threadMutex);
procVec.push_back(std::thread([sras, i]() {
std::thread(lamb, sras[i], std::this_thread::get_id()).detach();
}));
這方面的問題:
- 程式終止,可能是可連接執行緒處于活動狀態,離開范圍
uj5u.com熱心網友回復:
鑒于您展示的示例相當簡單,一個固定大小的 for 回圈,沒有奇怪的依賴關系,一個非常簡單的解決方案可能是使用 OpenMP,它允許您通過添加一行來執行您描述的操作(前提是我理解正確)
void multi_file_proc(std::vector<OBJ> objs, int n) {
std::vector<std::thread> procVec;
#pragma omp parallel for num_threads(n) schedule(dynamic, 1)
for (int i = 0; i < objs.size(); i ) {
/*
...
*/
}
}
在 for 回圈前面。當然,您必須修改您的編譯命令以添加 openmp 支持,精確的標志自然會因編譯器而異,即 -fopenmp 用于 g ,-qopenmp 用于 icpc 等。
上面的行基本上指示編譯器創建代碼以并行執行下面的 for 回圈。這里重要的一點是我們設定時間表的最后一個。動態只是意味著順序不是預先確定的,相反,當執行緒完成最后一個迭代時,它們將獲得下一次迭代。那里的整數 1 定義了它們一次執行的步驟數,考慮到每個檔案都很大,我們想要一些細粒度的東西,因為我們不期望調度有太多的開銷。
需要注意的是,OpenMP 與大多數 C 一樣,甚至不會試圖阻止您在自己的腳下開槍。有了并發,就有了全新的方法來做到這一點。
最后,這決不能保證絕對是絕對的最佳解決方案。例如,如果您的檔案長度不同,那么您可能希望在回圈之前將物件從最長到最短排序。這樣,一旦處理了最后一個物件(在某些時候只有一個執行緒將處理最終物件),就不會花費太長時間。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/514875.html
