[英]deadlock in using data for mutex and waits
對於並發C ++編程,我需要一些幫助。 我有一個名為"names.txt"
的名稱文件,格式如下:
0 James
1 Sara
2 Isaac
我還有一個名為"op.txt"
文件,其中包含對名稱文件的某些操作,格式為:
0 1 + // this means add Sara to James and store it in 0 position
1 2 $ // this means swap values in position 1 and position 2
以及具有操作輸出的文件"output.txt"
,格式為:
0 JamesSara
1 Isaac
2 Sara
問題是創建一個用於讀取names.txt
和op.txt
的線程並將其存儲。 接下來,創建一些變量線程以同時執行操作,最后在線程中執行output.txt
。
這是我針對此問題的代碼,當並發線程數大於2時,它可以正常工作。但是1和2線程的輸出不正確。 我在這段代碼中錯過了什么?
#include <fstream>
#include <iostream>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <deque>
using namespace std;
std::mutex _opMutex;
std::condition_variable _initCondition;
std::condition_variable _operationCondition;
int _counter = 0;
int _initCounter = 0;
int _doOperationCounter = 0;
struct OperationStruct
{
int firstOperand;
int secondOperand;
char cOperator;
};
const int THREADS = 5;
std::deque<std::pair<int, string> > _nameVector;
std::deque<OperationStruct> _opStructVec;
void initNamesAndOperations()
{
ifstream infile;
std::pair<int, string> namePair;
infile.open("names.txt");
if (!infile)
{
cout << "Unable to open file";
exit(-1);
}
int id;
string value;
while (infile >> id >> value)
{
namePair.first = id;
namePair.second = value;
_nameVector.push_back(namePair);
}
infile.close();
infile.open("op.txt");
if (!infile)
{
cout << "Unable to open file";
exit(-1);
}
int firstOperand;
int secondOperand;
char cOperator;
while (infile >> firstOperand >> secondOperand >> cOperator)
{
OperationStruct opSt;
opSt.firstOperand = firstOperand;
opSt.secondOperand = secondOperand;
opSt.cOperator = cOperator;
_opStructVec.push_back(opSt);
++_initCounter;
}
infile.close();
return;
}
void doOperationMath(int firstIndex, string firstValue, string secondValue, char cOp)
{
//basic mathematics
switch (cOp)
{
case '+':
{
for (int i = 0; i < _nameVector.size(); ++i)
{
std::pair<int, string> acc = _nameVector[i];
if (acc.first == firstIndex)
{
acc.second = firstValue + secondValue;
_nameVector[i].second = acc.second;
}
}
}
break;
default:
break;
}
++_doOperationCounter;
}
void doOperationSwap(int firstIndex, int secondIndex, string firstValue, string secondValue)
{
//swap
for (int i = 0; i < _nameVector.size(); ++i)
{
if (_nameVector[i].first == firstIndex)
_nameVector[i].second = secondValue;
if (_nameVector[i].first == secondIndex)
_nameVector[i].second = firstValue;
}
++_doOperationCounter;
}
void doOperations()
{
while (_doOperationCounter < _initCounter)
{
std::unique_lock<mutex> locker(_opMutex);
_initCondition.wait(locker, [](){return !_opStructVec.empty(); });
OperationStruct opSt = _opStructVec.front();
_opStructVec.pop_front();
locker.unlock();
_operationCondition.notify_one();
int firstId = opSt.firstOperand;
int secondId = opSt.secondOperand;
char cOp = opSt.cOperator;
string firstValue = "";
string secondValue = "";
for (int j = 0; j < _nameVector.size(); ++j)
{
std::pair<int, string> acc = _nameVector[j];
if (firstId == acc.first)
firstValue = acc.second;
if (secondId == acc.first)
secondValue = acc.second;
}
if (cOp == '$')
{
doOperationSwap(firstId, secondId, firstValue, secondValue);
}
else
{
doOperationMath(firstId, firstValue, secondValue, cOp);
}
}
return;
}
void doOutputFile()
{
ofstream outfile;
outfile.open("sampleOutput.txt", std::ios::out | std::ios::app);
if (!outfile)
{
cout << "Unable to open the file";
exit(-1);
}
while (_counter < _initCounter)
{
std::unique_lock<mutex> locker(_opMutex);
_operationCondition.wait(locker, [](){return !_nameVector.empty(); });
auto accPair = _nameVector.front();
_nameVector.pop_front();
locker.unlock();
outfile << accPair.first << " " << accPair.second << endl;
++_counter;
}
return;
}
int main()
{
thread th1(initNamesAndOperations);
std::vector<thread> operationalThreads;
for (int i = 0; i < THREADS; ++i)
{
operationalThreads.push_back(thread(doOperations));
}
thread th3(doOutputFile);
th1.join();
for (auto& opthread : operationalThreads)
opthread.join();
th3.join();
return 0;
}
如果從多個線程修改了變量,則可能必須使用一些同步來確保讀取正確的值。 最簡單的方法可能是對變量使用std::atomic
來確保操作正確排序。
另外,您的代碼中沒有任何內容可以確保您在讀取整個文件之前不會完成doOperations
線程。
顯然,您需要先讀取整個數據,或者有一種方法來等待某些數據可用(或到達數據末尾)。 如果讀取初始數據快而處理慢,那么更簡單的解決方案是在開始處理線程之前讀取數據。
可能發生的情況是,如果創建了很多線程,那么在創建最后一個線程時, initNamesAndOperations
將會讀取整個文件。
我強烈建議您購買和閱讀Anthony Williams 撰寫的C ++ Concurrency in Action 。 通過閱讀此類書籍,您將對現代C ++多線程有一個很好的了解,並且將有助於您編寫正確的代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.