Multi-threaded file reading produces the same result for each thread - c++

Basically, the issue I am having is in the title, I am trying to create a multi-threaded application to read and sum up the contents of a file, this works correctly with one thread. However, when more are introduced they come out with the same output. How do I fix this?
The code
void *sumThread(void *);
pthread_mutex_t keepOut = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t keepOutSum = PTHREAD_MUTEX_INITIALIZER;
int counter = 0, line_count = 0;
char* loc;
double total = 0;
void split(const string& s, char c, vector<string>& v)
{
string::size_type i = 0;
string::size_type j = s.find(c);
while (j != string::npos)
{
v.push_back(s.substr(i, j - i));
i = ++j;
j = s.find(c, j);
if (j == string::npos)
v.push_back(s.substr(i, s.length()));
}
}
int main(int argc, char* argv[])
{
if (argc < 2)
{
cerr << "Usage: " << argv[0] << " filename" << endl;
return 1;
}
string line;
loc = argv[1];
ifstream myfile(argv[1]);
myfile.unsetf(ios_base::skipws);
line_count = std::count(std::istream_iterator<char>(myfile),
std::istream_iterator<char>(),
'\n');
myfile.clear();
myfile.seekg(-1, ios::end);
char lastChar;
myfile.get(lastChar);
if (lastChar != '\r' && lastChar != '\n')
line_count++;
myfile.setf(ios_base::skipws);
myfile.clear();
myfile.seekg(0, ios::beg);
pthread_t thread_id[NTHREADS];
for (int i = 0; i < NTHREADS; ++i)
{
pthread_create(&thread_id[i], NULL, sumThread, NULL);
}
for (int i = 0; i < NTHREADS; ++i)
{
pthread_join(thread_id[i], NULL);
}
cout << setprecision(2) << fixed << total << endl;
return 0;
}
void *sumThread(void *)
{
pthread_mutex_lock(&keepOut);
int threadNo = counter;
counter++;
pthread_mutex_unlock(&keepOut);
ifstream myfile(loc);
double runningTotal = 0;
string line;
if (myfile.is_open())
{
for (int i = threadNo; i < line_count; i += NTHREADS)
{
vector < string > parts;
getline(myfile, line);
// ... and process out the 4th element in the CSV.
split(line, ',', parts);
if (parts.size() != 3)
{
cerr << "Unable to process line " << i
<< ", line is malformed. " << parts.size()
<< " parts found." << endl;
continue;
}
// Add this value to the account running total.
runningTotal += atof(parts[2].c_str());
}
myfile.close();
}
else
{
cerr << "Unable to open file";
}
pthread_mutex_lock(&keepOutSum);
cout << threadNo << ": " << runningTotal << endl;
total += runningTotal;
pthread_mutex_unlock(&keepOutSum);
pthread_exit (NULL);
}
Sample output
2: -46772.4
0: -46772.4
1: -46772.4
3: -46772.4
-187089.72
Each thread is supposed to read and sum up the numbers in the file, then add them together when it's done. However, the threads all seem to return the same number even though the threadNo variable a clearly different as indicated in the output.

Your problem is here:
for (int i = threadNo; i < line_count; i += NTHREADS) {
vector<string> parts;
getline(myfile, line);
getline() doesn't know the value of i, so it is still reading adjacent lines from the file, without skipping any lines. Hence all threads are reading the same first few lines of the file.

Related

C++ code crashes instantly due to memory issues

This code should read a .pnm file. I tried to run it with 2 resolutions:
200x200 px: Here everything works just fine.
500x281 px: Code instantly crashes, raising a SIGSEGV error.
As far as I know, SIGSEGV is related to memory issues. I have 8GB of RAM, a quantity that I judge to be enough to run this. I don't have any idea about why it's happening and how to fix it.
Code
#define IO_ERROR (5)
#define X_DIMENSION (500)
#define Y_DIMENSION (281)
#define C_DIMENSION (3)
#define HEADER_SIZE (3)
#define BODY_SIZE (X_DIMENSION * Y_DIMENSION * C_DIMENSION)
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int readImage(string fileName, string *imgHeader, string *imgBody)
{
ifstream inputFile(fileName);
if (!inputFile.is_open())
return IO_ERROR;
string line;
int count = 0;
while (getline(inputFile, line)) {
if (line.find("#") != string::npos)
continue;
if (count < 3)
imgHeader[count] = line;
else
imgBody[count - HEADER_SIZE] = line;
count++;
}
inputFile.close();
return 0;
}
void numericParser(const string *imgBody, unsigned char *numericBody)
{
int i = 0;
while(i < BODY_SIZE) {
numericBody[i] = (unsigned) atoi(imgBody[i].c_str());
i++;
}
}
void rgbParser(const string *imgBody, unsigned char rgbMatrix[X_DIMENSION][Y_DIMENSION][C_DIMENSION])
{
unsigned char numericBody[BODY_SIZE];
numericParser(imgBody, numericBody);
int k = 0;
for (int i = 0; i < X_DIMENSION; i++) {
for (int j = 0; j < Y_DIMENSION; j++) {
for (int c = 0; c < 3; c++) {
rgbMatrix[i][j][c] = numericBody[k];
k++;
}
}
}
}
void printInfo(const string *header, const string *body)
{
cout << "#-*- Image Header -*-" << endl;
for (int i = 0; i < HEADER_SIZE; i++) {
cout << header[i] << endl;
}
cout << "#-*- Image Body -*-";
for (int i = 0; i < 5 * C_DIMENSION; i++) {
if (i % 3 == 0) cout << endl << "R: " << body[i];
else if (i % 3 == 1) cout << " G: " << body[i];
else cout << " B: " << body[i];
}
cout << endl << ". . ." << endl;
}
int main()
{
string fileName;
cout << "File name: ";
cin >> fileName;
string imgHeader[HEADER_SIZE];
string imgBody[BODY_SIZE];
if(readImage(fileName, imgHeader, imgBody) == IO_ERROR)
return IO_ERROR;
// printInfo(imageData);
unsigned char rgbMatrix[X_DIMENSION][Y_DIMENSION][C_DIMENSION];
rgbParser(imgBody, rgbMatrix);
return 0;
}
Additional Info
I'm on Arch Linux 64-bit, using CLion as IDE.

program to check is there any alphabet(a-z) exists in all string(list of novels) and print number of alphabets found

will you please tell me what will be the procedure to find alphabet occur in all strings(char string lists) in c++
the output will only return matched values(alphabet numbers)
i m trying this
#include <vector>
#include <iostream>
#include <cstdio>
int main()
{
//setup
std::vector<int> alphabetCount;
for (int i = 0; i < 26; ++i)
{
alphabetCount.push_back(0);
}
//now the interactive bit
std::cout << "Enter a line of text\n";
std::string line;
std::getline(std::cin, line);
for (size_t i = 0; i < line.size(); ++i)
{
char currentChar = tolower(line[i]);
if (isalpha(currentChar))
{
++alphabetCount[currentChar - 'a']; //subtract a, so if currentChar = a, 'a' - 'a' = 0, so its index 0
}
}
for (size_t i = 0; i < alphabetCount.size(); ++i)
{
std::cout << "there were " << alphabetCount[i] << " occurences of " << static_cast<char>(i + 'a') << "\n"; //add 'a' for the same reason as above, though we have to cast it to a char.
}
system("pause");
return 0;
}
but it only returns values from single string i want result from all string
The reason why it is taking one string at a time is because you are taking one as input, you should make a vector of string and take input in it.
You have not read the string more than once in program. below is sample program, which is very naive to demonstrate the process. The loop terminating condition can be much better than mine though.
int main()
{
//setup
std::vector<int> alphabetCount;
for (int i = 0; i < 26; ++i)
{
alphabetCount.push_back(0);
}
//now the interactive bit
std::cout << "Enter a line of text\n";
std::string line;
do{
std::getline(std::cin, line);
for (size_t i = 0; i < line.size(); ++i)
{
char currentChar = tolower(line[i]);
if (isalpha(currentChar))
{
++alphabetCount[currentChar - 'a']; //subtract a, so if currentChar = a, 'a' - 'a' = 0, so its index 0
}
}
}while(line != "exit");
--alphabetCount['e' - 'a'];
--alphabetCount['x' - 'a'];
--alphabetCount['i' - 'a'];
--alphabetCount['t' - 'a'];
for (size_t i = 0; i < alphabetCount.size(); ++i)
{
std::cout << "there were " << alphabetCount[i] << " occurences of " << static_cast<char>(i + 'a') << "\n"; //add 'a' for the same reason as above, though we have to cast it to a char.
}
system("pause");
return 0;
}

I keep getting subscript out of range don't know how to fix it [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
#include <iostream>
#include <fstream>
#include <string>
#include <ctime>
#include <cstdlib>
using namespace std;
const int MAX_NUMS = 200; // Constant for the maximum number of words.
const int MAX_GUESSES = 8;
const string LETTERS = "abcdefghijklmnopqrstuvwxyz";
char inputLetter();
int findChar(char letter, string&word);
string getGuessedWord(string&secretWord, string&lettersGuessed);
string getLettersGuessed(char letter, string&lettersGuessed, int n);
void display(string&lettersGuessed, string&wordGuessed, int num, int pos);
bool isDone(string wordGuessed);
int main()
{
string oneWord; // holds one word from input file
string secretWord; // holds secret word to be guessed
string words[MAX_NUMS]; // holds list of words from input file
int randomValue; // holds index of secret word
int count = 0; // holds number of words in the file
// Declare an ifstream object named myFile and open an input file
ifstream myFile;
myFile.open("P4Words.txt");
// Exit program if cannot open file for input
if (!myFile)
{
cout << "Error: Unable to open file for input" << endl;
return 0;
}
// Input words from a file into words array
// Add your code here ...
myFile >> oneWord;
while (!myFile.eof())
{
words[count] = oneWord;
count++;
myFile >> oneWord;
}
myFile.close();
cout << count << " words loaded." << endl;
srand(static_cast<unsigned int>(time(0)));
// Select a secret word
// Add your code here ...
secretWord = words[rand() % (count + 1) ];
// Possible useful variables the loop
string lettersGuessed = ""; // holds letters guessed so far
string wordGuessed; // holds current word guessed like �_ pp_ e�
int incorrectGuesses = 0; // holds number of incorrect guesses so far
char letter; // holds a guessed letter
bool done = false; // have not guessed the word yet
int num = 8; int pos;
cout << "Welcome to the game, Hangman V1 by Your Name!" << endl;
cout << "I am thinking of a word that is " << secretWord.length()
<< " letters long." << endl;
// Set up a loop to input guesses and process
// Add your code here ...
do
{
letter = inputLetter();
pos = findChar(letter, secretWord);
wordGuessed = letter;
lettersGuessed = getLettersGuessed(letter, lettersGuessed, 8 - num);
wordGuessed = getGuessedWord(secretWord, lettersGuessed);
display(lettersGuessed, wordGuessed, num, pos);
done = isDone(wordGuessed);
num--;
} while ((num > 1) && (done == false));
// Check for won or lost
// Add your code here ...
if (done == false)
{
cout << "sorry you lose..." << endl;
}
if (done == true)
{
cout << "congratulations! " << endl;
}
system("pause"); // stop program from closing, Windows OS only
return 0;
}
// Add function definitions here ...
char inputLetter()
{
int i;
char letter;
do
{
cout << "please guess a letter: " << endl;
cin >> letter;
for (i = 0; i < 25; i++)
{
if (letter == LETTERS[i])
{
return letter;
}
}
if (letter != LETTERS[i])
{
cout << "Oops! That is an invalid character." << endl;
}
} while (letter != LETTERS[i]);
}
int findChar(char letter, string &word)
{
int i = 0; int pos = 0; bool found = false;
do
{
if (word[pos] == letter)
{
return pos;
found = true;
}
pos++;
} while (pos<word.length() - 1);
if (found == false)
{
return -1;
}
}
string getGuessedWord(string&secretWord, string&letterGuessed)
{
string temp;
temp = secretWord;
for (size_t k = 0; k <= temp.length() - 1; k++)
{
temp[k] = '_';
}
for (size_t i = 0; i <= temp.length() - 1; i++)
{
for (size_t j = 0; j <= temp.length() - 1; j++)
{
if (letterGuessed[i] == secretWord[j])
{
temp[j] = letterGuessed[i];
}
}
}
return temp;
}
string getLettersGuessed(char letter, string&lettersGuessed, int n)
{
string temp;
temp = letter;
lettersGuessed.insert(n, temp);
return lettersGuessed;
}
void display(string&lettersGuessed, string&wordGuessed, int num, int pos)
{
if (pos != -1)
{
cout << "You have " << num << " guesses left." << endl;
cout << "Letters guessed so far: " << lettersGuessed << endl;
cout << "Good guess!: " << wordGuessed << endl;
cout << "-----------------------------------------------------" << endl;
}
if (pos == -1)
{
cout << "You have " << num << " guesses left." << endl;
cout << "Letters guessed so far: " << lettersGuessed << endl;
cout << "Oops! that letter is not my word: " << wordGuessed << endl;
cout << "-----------------------------------------------------" << endl;
}
}
bool isDone(string wordGuessed)
{
bool done = false; int k = 0;
for (size_t i = 0; i <= wordGuessed.length() - 1; i++)
{
if (wordGuessed[i] == '_')
{
k++;
}
}
if (k == 0)
{
done = true;
}
return done;
}
it says subscript is out of range I need help to fix it
let me know how to fix it please its a project that is due very soon
that's all I got so far
Change:
for (size_t i = 0; i <= temp.length() - 1; i++)
to:
for (size_t i = 0; i <= letterGuessed.length() - 1; i++)

Program wont compile

Here is the code
#include <iostream>
#include <cstdlib>
#include <fstream>
using namespace std;
class sudoku {
public:
void read(ifstream ifs);
void write(ofstream ofs);
private:
int puzzle[9][9];
};
void sudoku::read(ifstream ifs){
int row;
int col;
int value;
int linenum = 1;
bool error = false;
while(ifs >> row){
ifs >> col;
ifs >> value;
if(row < 0 || row > 8){
cerr << "Incorrect Row Value: " << row << " Line Number: " << linenum;
error = true;
}
if(col < 0 || col > 8){
error = true;
cerr << "Incorrect Col Value: " << col << " Line Number: " << linenum;
}
if(value < 1 || value > 9){
error = true;
cerr << "Invalid Value: " << value << " Line Number: " << linenum;
}
if (! error)
puzzle[row][col] = value;
error = false;
}
}
void sudoku::write(ofstream ofs){
for (int i = 0; i < 9; i++){
for (int j = 0; j < 0; j++){
if(puzzle[i][j] != 0){
ofs << i << ' ' << j << ' ' << puzzle[i][j] << endl;
}
}
}
}
int main(int argc, char* argv[]){
sudoku sudopuzzle;
string filename = argv[1];
int found = filename.find(".txt");
if(found == filename.npos) {
cout << "No .txt extension" << endl;
return 0;
}
ifstream ifs;
ifs.open(filename.c_str());
sudopuzzle.read(ifs);
ifs.close();
filename.resize(filename.size()-4);
filename.append("_checked.txt");
ofstream ofs;
ofs.open(filename.c_str());
sudopuzzle.write(ofs);
ofs.close();
return 0;
}
This program is supposed to read a generated puzzle. make sure its valid and write it to another file. Normally I am good at figuring out errors but this one is a mess. It spits out stuff referring to the inclusion of iostream and cites files that I have nothing to do with. Im guessing its some error that comes with passing fstreams to funcitons or something. any clue?
You should be passing a reference to the stream objects:
class sudoku {
public:
void read(ifstream &ifs);
void write(ofstream &ofs);
private:
int puzzle[9][9];
};
void sudoku::read(ifstream &ifs){
// sudoku::read code here
}
void sudoku::write(ofstream &ofs){
// sudoku::write code here
}
This change is required because both ifstream and ofstream have a =delete copy constructor. (Hat tip: #awesomeyi)

Argument - command prompts c++

So I'm trying to finish a part of a program where I have to find the last n-1 words in a vector string and shift the next word in source into the end of the vector string. Here I'm trying to write the function for 'findAndShift' and use arguments from another program to use it.
This is my part of the program.
void findAndShift(vector<string>& ngram, string source[],int sourceLength) {
if (argc == 2)///default command prompt...not declared?
{
ifstream infile;
infile.open(argv[1], ios::in);
if (infile.fail())
{
cout << argv[0] << ": "<< argv[i] << "I'm afraid I can't let you do that, Dave." << endl;
}
else
{
//get length of n
infile.seekg(0, ios::end);
const int sourceLength = infile.tellg();
int n = 0;
string word;
ngram = rand() % sourceLength;
while (!infile.eof())
{
infile >> source;
++n;
if(counter == ngram);
word = n;
}
}
}
return;
}
Here's the program I have to use for mine.
string source[250000];
vector<string> ngram;
int main(int argc, char* argv[]) {
int n, outputN, sl;
n = 3;
outputN = 100;
for (int i = 0; i < argc; i++) {
if (string(argv[i]) == "--seed") {
srand(atoi(argv[i+1]));
} else if (string(argv[i]) == "--ngram") {
n = 1 + atoi(argv[i+1]);
} else if (string(argv[i]) == "--out") {
outputN = atoi(argv[i+1]);
} else if (string(argv[i]) == "--help") {
help(argv[0]);
return 0; }
}
fillWordList(source,sl);
cout << sl << " words found." << endl;
cout << "First word: " << source[0] << endl;
cout << "Last word: " << source[sl-1] << endl;
for (int i = 0; i < n; i++) {
ngram.push_back(source[i]);
}
cout << "Initial ngram: ";
put(ngram);
cout << endl;
for (int i = 0; i < outputN; i++) {
if (i % 10 == 0) {
cout << endl;
}
//put(ngram);
//cout << endl;
cout << ngram[0] << " ";
findAndShift(ngram, source, sl);
} }
Any ideas?
you have to pass more argument in your program argc and argv[] as argc is just a parameter for main function and hence is not visible in other function.
Here is your modified code.
void findAndShift(vector<string>& ngram, string source[],int sourceLength, int argc, char argv[0], argv[1],argv[i]){
if (argc == 2)///default command prompt...not declared?
{
ifstream infile;
infile.open(argv[1], ios::in);
if (infile.fail())
{
cout << argv[0] << ": "<< argv[i] << "I'm afraid I can't let you do that, Dave." << endl;
}
else
{
//get length of n
infile.seekg(0, ios::end);
const int sourceLength = infile.tellg();
int n = 0;
string word;
ngram = rand() % sourceLength;
while (!infile.eof())
{
infile >> source;
++n;
if(counter == ngram);
word = n;
}
}
}
return;
}
your main code
string source[250000];
vector<string> ngram;
int main(int argc, char* argv[]) {
int n, outputN, sl;
n = 3;
outputN = 100;
for (int i = 0; i < argc; i++) {
if (string(argv[i]) == "--seed") {
srand(atoi(argv[i+1]));
} else if (string(argv[i]) == "--ngram") {
n = 1 + atoi(argv[i+1]);
} else if (string(argv[i]) == "--out") {
outputN = atoi(argv[i+1]);
} else if (string(argv[i]) == "--help") {
help(argv[0]);
return 0; }
}
fillWordList(source,sl);
cout << sl << " words found." << endl;
cout << "First word: " << source[0] << endl;
cout << "Last word: " << source[sl-1] << endl;
for (int i = 0; i < n; i++) {
ngram.push_back(source[i]);
}
cout << "Initial ngram: ";
put(ngram);
cout << endl;
for (int i = 0; i < outputN; i++) {
if (i % 10 == 0) {
cout << endl;
}
//put(ngram);
//cout << endl;
cout << ngram[0] << " ";
findAndShift(ngram, source, sl, argc,argv[0],argv[1],argv[i]);
} }
I haven''t tested it.
If it still not work try to use char * in argument list of findAndShift
Hope it helps....