I am facing some problems when I am trying to read a class variable in my worker thread (That variable was not created withing that thread). Here is my class header with static worker thread function:
class C1WTempReader
{
public:
C1WTempReader(std::string device);
virtual ~C1WTempReader();
void startTemRead();
double& getTemperature();
private:
std::string device;
std::string path;
double temperature;
pthread_t w1Thread;
std::mutex w1Mutex;
bool fileExists(const std::string& filename);
static void * threadHelper(void * arg)
{
return ((C1WTempReader*) arg)->tempReadRun(NULL);
}
void* tempReadRun(void* arg);
};
Here are the crucial methods I am using:
C1WTempReader::C1WTempReader(std::string device)
{
path = W1_PATH + device + W1_SLAVE;
if (!fileExists(path))
{
std::cout << "File " << path << " doesnt exist!" << std::endl;
path.clear();
return;
}
std::cout << "1 wire termometer device path: " << path << std::endl;
}
void C1WTempReader::startTempRead()
{
if(pthread_create(&w1Thread, NULL, threadHelper, NULL) == -1)
{
std::cout << "1W thread creation failed" << std::endl;
}
}
void* C1WTempReader::tempReadRun(void* arg)
{
w1Mutex.lock(); // SEGFAULT
std::string line;
std::ifstream myfile (path.c_str());
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
size_t found = line.find("t=");
if (found != std::string::npos)
{
found += 2;
std::string temp = line.substr(found, 10);
temperature = atof(temp.c_str());
temperature /= 1000;
std::cout << "Temperature: " << temperature << " *C" << std::endl;
}
line.clear();
}
myfile.close();
}
else
{
std::cout << "Unable to open file" << std::endl;
temperature = 1000; // bad value
}
w1Mutex.unlock();
return NULL;
}
double& C1WTempReader::getTemperature()
{
if (pthread_join(w1Thread, NULL))
{
std::cout << "1W Unable to join thread!" << std::endl;
}
return temperature;
}
Segmentation fault happens in the tempReadRun method, as soon as I try to lock the mutex. I didnt have mutexes before and I noticed that it happens whenever I try to read any of the class variables that are created ruring the class creation and are not created within the new thread. What Am I doing wrong?
And heres how I am trying to run this:
string device = "28-00000713a636";
C1WTempReader tempReader(device);
tempReader.startTempRead();
.
.
.
double temp = tempReader.getTemperature();
I have found what the problem was. In the function C1WTempReader::startTempRead():
if(pthread_create(&w1Thread, NULL, threadHelper, NULL) == -1)
{
std::cout << "1W thread creation failed" << std::endl;
}
The last argument of pthread_create had to be changed to this.
You are not passing argument to pthread_create:
if(pthread_create(&w1Thread, NULL, threadHelper, this) == -1)
Related
I've made this simple program according to a github code.
All you have to take care of is the while loop at the end of the main() method.
#include "SDL2\SDL.h"
constexpr const char* WAV_PATH = "applause.wav";
#include <iostream>
static Uint8* sg_pAudioPos;
static Uint32 sg_AudioLength;
struct CWavWrapper
{
Uint32 m_Length;
Uint8* m_pBuffer;
SDL_AudioSpec m_Spec;
};
void ExitProgram(int code = 0)
{
system("pause");
exit(code);
}
void AudioCallback(void* pData, Uint8* pStream, int Length);
#undef main
int main()
{
using std::cout;
using std::cerr;
using std::endl;
if (SDL_Init(SDL_INIT_AUDIO) < 0)
{
cerr << "couldnt init audio: " << SDL_GetError() << endl;
ExitProgram(1);
}
cout << "Loading wav... " << WAV_PATH << endl;
static CWavWrapper Wav;
if(SDL_LoadWAV(WAV_PATH,&Wav.m_Spec,&Wav.m_pBuffer,&Wav.m_Length) == NULL)
{
cerr << "couldnt load wav: " << SDL_GetError() << endl;
ExitProgram(1);
}
Wav.m_Spec.callback = AudioCallback;
Wav.m_Spec.userdata = NULL;
sg_pAudioPos = Wav.m_pBuffer;
sg_AudioLength = Wav.m_Length;
cout << "Opening Audio..." << endl;
if (SDL_OpenAudio(&Wav.m_Spec, NULL) < 0)
{
cerr << "couldn't open audio: " << SDL_GetError() << endl;
ExitProgram(1);
}
cout << "Success! Starting Audio..." << endl;
SDL_PauseAudio(0);
while (sg_AudioLength > 0)
{
//If I remove this output line or as in the GitHub example not do the SDL_Delay() the wav gets played infinitely.
//how does printing out a variable change its value (as it should do only in the callback)?
cout << "sg_AudioLength: " << sg_AudioLength << endl;
}
SDL_CloseAudio();
SDL_FreeWAV(Wav.m_pBuffer);
ExitProgram(0);
}
void AudioCallback(void* pData, Uint8* pStream, int Length)
{
if (sg_AudioLength == 0)
return;
if (Length > sg_AudioLength)
{
Length = sg_AudioLength;
}
SDL_MixAudio(pStream, sg_pAudioPos, Length, SDL_MIX_MAXVOLUME);
sg_pAudioPos += Length;
sg_AudioLength -= Length;
}
As you can see at the end of the main() function, I put a description on what happens when I remove the cout line.
I think it might has to do something with the AudioCallback only being called when a certain code is done. But I am not sure and I would like to get an answer to it.
EDIT: I've noticed that when anything gets processed in the while loop, the audio seems to play right. Does anything from compiling to run time notice that the loop does not change the variable and thinks that this is now an endless loop so the loop does not even try to check the variable again?
I've added some slight multi threading to a simple c++ program and have encountered a few issues along the way.
The latest of these issues is that historical::assignthreads for some reason is receiving an empty vector from the function historical::writeData.
Looking at the code below you will see that writeData iterates through a vector and puts the data in a placeholder before sending it forward to assignthreads (after 5 iterations) - meaning that the vector being sent from writeData to assignthreads shouldn't be empty.
However in assignthreads you will see that there are two cout:s, one before and one after the loop. Both writes to cout without the loop even starting.
Does anyone have any idea of how this could be the case?
void historical::writeData(std::vector<std::vector<std::wstring>> in, const string& symbol) {
std::cout << "Sending data to database connector" << std::endl;
std::vector<std::vector<std::wstring>> temp;
std::vector<std::vector<std::wstring>>::iterator it;
int count = 0;
for (it = in.begin(); it != in.end(); it++) {
if (count = 5) {
cout << "I'm in count 5" << endl;
assignthreads(temp, symbol);
temp.clear();
count = 0;
}
else {
cout << "I'm in count 0" << endl;
temp.push_back(*it);
count++;
}
}
if (!temp.empty()) {
cout << "I'm in empty" << endl;
assignthreads(temp, symbol);
}
else cout << "I'm empty!!" << endl;
}
void historical::assignthreads(std::vector<std::vector<std::wstring>>& partVec, const string& symbol) {
int i = 0;
cout << "I'm in assign" << endl;
vector<thread> threads(size(partVec));
std::vector<std::vector<std::wstring>>::iterator it;
for (it = partVec.begin();
it != partVec.end();
it++) {
cout << "I'm in the loop" << endl;
std::shared_ptr<database_con> sh_ptr(new database_con);
threads.at(i) = std::thread(&database_con::start, sh_ptr, *it, symbol);
i++;
}
cout << "I've finished" << endl;
for (auto& th : threads) th.join();
}
void historical::writer(string* pInput) {
ofstream mf("test.csv");
if (mf.is_open()) {
mf << *pInput;
mf.close();
}
else cout << "Unable to open file" << endl;
}
Your fundamental problem here is that count = 5 is an assignment and is therefore always true. You intended to use count == 5.
It's worth noting that particularly as your vector becomes large copying it is very wasteful, and you're doing this 2 ways:
The vector is passed into writeData by value, change to copying by reference: void writeData(std::vector<std::vector<std::wstring>>& in, const string& symbol)
temp will eventually copy every element of in, use iterators instead so your code would have to change to:
#define SIZE 5
void assignthreads(std::vector<std::vector<std::wstring>>::iterator start, std::vector<std::vector<std::wstring>>::iterator finish, const string& symbol) {
cout << "I'm in assign" << endl;
vector<thread> threads(distance(start, finish));
for(auto i = 0; start != finish; ++i, ++start) {
cout << "I'm in the loop" << endl;
std::shared_ptr<database_con> sh_ptr(new database_con);
threads.at(i) = std::thread(&database_con::start, sh_ptr, *start, symbol);
}
cout << "I've finished" << endl;
for (auto& th : threads) th.join();
}
void writeData(std::vector<std::vector<std::wstring>>& in, const string& symbol) {
std::cout << "Sending data to database connector" << std::endl;
auto count = 0;
while(count < in.size() - SIZE) {
auto start = next(in.begin(), count);
count += SIZE;
auto finish = next(in.begin(), count);
assignthreads(start, finish, symbol);
}
assignthreads(next(in.begin(), count), in.end(), symbol);
cout << "I'm empty!!" << endl;
}
I have a highscore system implemented using SQLite for a c++ shooter ive made but it only refreshes when I relaunch the game, I think this is because it only re- sorts from largest to smallest on game launch. I don't know why this is, it does seem to record all game scores as it should, but I think it is only ordering them on launch. How could I make it so it re-orders before it prints to screen. Here is the code
in main.cpp
case eHIGH_SCORES:
DrawString( "HIGHSCORES", iScreenWidth * 0.38, iScreenHeight * 0.95);
DrawString( "PRESS C TO CLOSE", iScreenWidth * 0.32, iScreenHeight * 0.1);
DatabaseMaker DatabaseMaker("MyDatabase.db");
DatabaseMaker.CreateDatabase();
DatabaseMaker.CreateTable("HIGHSCOREST");
if (scorer<1)
{
DatabaseMaker.InsertRecordIntoTable("HIGHSCOREST",scoreArray);
scorer++;
for (int i=0; i<10; i++)
{
scoreArray[i]=0;
}
}
DatabaseMaker.RetrieveRecordsFromTable("HIGHSCOREST");
DatabaseMaker.databaseprinter();
then in the Database maker class I have
DatabaseMaker::DatabaseMaker(std::string HighScoresT)
{
this->HighScores = HighScoresT;
myDatabase = NULL;
}
int DatabaseMaker::Callback(void* notUsed, int numRows, char **data, char **columnName)
{
for(int i = 0; i < numRows; i++)
{
std::cout << columnName[i] << ": " << data[i] << std::endl;
holder.push_back(atoi(data[i]));
}
return 0;
}
void DatabaseMaker::databaseprinter()
{
for (int i = 0; i < 10; i++)
{
itoa(holder[i], displayHolder, 10);
DrawString(displayHolder, 780/2, 700-(50*i));
}
}
void DatabaseMaker::CreateDatabase()
{
int errorCode = sqlite3_open(HighScores.c_str(), &myDatabase);
if(errorCode == SQLITE_OK)
{
std::cout << "Database opened successfully." << std::endl;
}
else
{
std::cout << "An error has occured." << std::endl;
}
}
void DatabaseMaker::CreateTable(std::string HIGHSCOREST)
{
char* errorMsg = NULL;
std::string sqlStatement;
sqlStatement = "CREATE TABLE HIGHSCOREST(" \
"ID INT," \
"SCORE INT);";
sqlite3_exec(myDatabase, sqlStatement.c_str(), Callback, 0, &errorMsg);
if(errorMsg != NULL)
{
std::cout << "Error message: " << errorMsg << std::endl;
}
}
void DatabaseMaker::InsertRecordIntoTable(std::string HIGHSCOREST,int (&scoreArray)[10] )
{
char*errorMsg = NULL;
std::string sqlStatement;
int x=5;
for(int i=0;i<10;i++)
{
std::string scorestring;
scorestring = std::to_string(scoreArray[i]);
sqlStatement = "INSERT INTO HIGHSCOREST (ID,SCORE)" \
"VALUES (1,"+scorestring+");";
sqlite3_exec(myDatabase, sqlStatement.c_str(), Callback, 0, &errorMsg);
if(errorMsg != NULL)
{
std::cout << "Error message: " << errorMsg << std::endl;
}
}
}
void DatabaseMaker::RetrieveRecordsFromTable(std::string HIGHSCOREST)
{
char* errorMsg = NULL;
std::string sqlStatement;
sqlStatement = "SELECT SCORE from HIGHSCOREST order by SCORE desc;";
sqlite3_exec(myDatabase, sqlStatement.c_str(), Callback, 0, &errorMsg);
if(errorMsg != NULL)
{
std::cout << "Error message: " << errorMsg << std::endl;
}
sqlite3_close(myDatabase);
}
DatabaseMaker::~DatabaseMaker()
{
}
Well, maybe try to move sqlite3_close statement off the RetrieveRecordsFromTable member function, maybe to destructor or seperate function?
Since you close connection to database after calling it for first time (and this might be a reason the problem is fixed by rerunning your application).
Also, consider changing this DatabaseMaker DatabaseMaker("MyDatabase.db"); into this: DatabaseMaker databaseMaker("MyDatabase.db");, otherwise you might have problem defining another DatabaseMaker in same scope.
I can't figure out where is the problem with this simple code, I think that here is the trouble with output to Console maybe deadlock or something, can somebody, please help.
#include <iostream>
#include <string>
#include <sstream>
#include <boost/thread.hpp>
using namespace std;
struct IntegrateTask
{
int id;
double from, to, step, result;
IntegrateTask(int id, double from, double to, double step)
{
this -> id;
this -> from = from;
this -> to = to;
this -> step = step;
}
~IntegrateTask()
{}
};
vector<IntegrateTask> * tasks = new vector<IntegrateTask>();
boost::mutex mutlist;
boost::mutex iomutex;
boost::condition_variable condtask;
bool isInterrupted = false;
double foo(double x)
{
return x * x;
}
void integrate(IntegrateTask * task)
{
double result = 0;
double step = task -> step;
for(double i = task -> from ; i != task -> to; i =+ step)
{
result += foo(i) * step;
}
task -> result = result;
}
void integrateThread()
{
boost::thread::id id = boost::this_thread::get_id();
try
{
{
boost::mutex::scoped_lock iolock(iomutex);
cout << "Thread #" << id << " is working!" << endl;
}
while(!isInterrupted)
{
IntegrateTask * currtask = NULL;
{
boost::mutex::scoped_lock lock(mutlist);
while(!isInterrupted && tasks -> empty())
{
condtask.wait(lock);
}
if (!tasks -> empty())
{
currtask = &tasks->back();
tasks->pop_back();
}
}
if (currtask != NULL)
{
integrate(currtask);
boost::mutex::scoped_lock iolock(iomutex);
cout << "Task #" << (currtask->id) << "; result = " << (currtask->result) << endl;
}
}
boost::mutex::scoped_lock iolock(iomutex);
cout << "Thread # " << id << " stoped working normal!" << endl;
}
catch(boost::thread_interrupted)
{
boost::mutex::scoped_lock ioLock(iomutex);
cout << "Thread # " << id << " stoped working by interruption!" << endl;
}
catch(exception & e)
{
boost::mutex::scoped_lock iolock(iomutex);
cout << "Error: " << e.what() << endl;
}
}
int main()
{
cout << "Function for integration: f(x)=x*x" << endl;
cout << "For stopping program press EXIT" << endl;
int thcount = 6;// or boost::thread::hardware_concurrency()
boost::thread_group thgroup;
for (int i = 1; i <= thcount; i++){
thgroup.create_thread(&integrateThread);
}
int id = 0;
while (true)
{
string line;
{
boost::mutex::scoped_lock iolock(iomutex);
cout << "Task #" << ++id << "; left bound, right bound and step: ";
getline(cin, line);
}
if (line.find("e") != string::npos)
{
isInterrupted = true;
condtask.notify_all();
thgroup.interrupt_all();
thgroup.join_all();
return 0;
}
double from, to, step;
istringstream input(line);
input >> from >> to >> step;
IntegrateTask * task = new IntegrateTask(id, from, to, step);
{
boost::mutex::scoped_lock lock(mutlist);
tasks->push_back(*task);
}
condtask.notify_one();
}
}
I haven't tried to follow the logic of what you're aiming to achieve here, but there are 2 issues (at least):
You're not using id in IntegrateTask's constructor. You should generally favour initialisation lists over assignments in constructor bodies, and using class member variable names in function signatures is a recipe for disaster too, so I'd change your constructor to:
IntegrateTask(int id_init, double from_init, double to_init, double step_init)
: from(from_init), to(to_init), step(step_init), id(id_init) {}
The probable cause of the hanging is your use of != in the for loop in integrate. If you change that to < your program shouldn't hang, but I'm not sure if this breaks your program's logic.
I have the following code, so far, I want to check if a file name is already in the linked list fileList (or flist). according to the output, the string saved in the first Node was changed somewhere in Node* getFileName(Node *&flist) How did this happen? Also, is there anything else that I'm doing is wrong or not safe regarding pointers of Node and strings?
output:
in main: file4.txt
start of process: file4.txt
file4.txt
mid of process: file4.txt"
in contains, fileName in node: file4.txt"
in contains, target file name: file4.txt
end of process: file4.txt"
0
no recursive call
code:
struct Node {
string fileName;
Node *link;
};
/*
*
*/
bool contains (Node *&flist, string &name) {
Node *tempNode = *&flist;
while (tempNode != 0) {
cout << "in contains, fileName in node: " << flist->fileName << endl;
cout << "in contains, target file name: " << name << endl;
if ((tempNode->fileName) == name) {
return true;
}
else {
tempNode = tempNode->link;
}
}
return false;
}
/*
*
*/
Node* getLastNode (Node *&flist) {
Node *tempNode = *&flist;
while (tempNode != 0) {
tempNode = tempNode->link;
}
return tempNode;
}
/*
*
*/
string getFileName(string oneLine) {
char doubleQuote;
doubleQuote = oneLine[9];
if (doubleQuote == '\"') {
string sub = oneLine.substr(10); //getting the file name
string::size_type n = sub.size();
sub = sub.substr(0,n-1);
cout << sub << endl;
return sub;
}
return NULL;
}
/*
*
*/
void process( istream &in, ostream &out, Node *&flist ) {
cout << "start of process: " << flist->fileName << endl;
string oneLine; //temp line holder
while (getline(in, oneLine)) {
// cout << oneLine << endl;
string::size_type loc = oneLine.find("#include",0);
if (loc != string::npos) {
//found one line starting with "#include"
string name;
name = getFileName(oneLine);
cout << "mid of process: " << flist->fileName << endl;
bool recursive;
recursive = contains(flist, name);
cout << "end of process: " << flist->fileName << endl;
cout << recursive << endl;
if (recursive) {
//contains recursive include
cerr << "recursive include of file " << name << endl;
exit(-1);
}
else {
//valid include
cout << "no recursive call" << endl;
}//else
}//if
}//while
}//process
/*
*
*/
int main( int argc, char *argv[] ) {
istream *infile = &cin; // default value
ostream *outfile = &cout; // default value
Node* fileList;
switch ( argc ) {
case 3:
outfile = new ofstream( argv[2] ); // open the outfile file
if ( outfile->fail() ) {
cerr << "Can't open output file " << argv[2] << endl;
exit( -1 );
}
// FALL THROUGH to handle input file
case 2:
infile = new ifstream( argv[1] ); // open the input file
if ( infile->fail() ) {
cerr << "Can't open input file " << argv[1] << endl;
exit( -1 );
}
else {
Node aFile = {argv[1], 0};
fileList = &aFile;
cout << "in main: " << fileList->fileName << endl;
}
// FALL THROUGH
case 1: // use cin and cout
break;
default: // too many arguments
cerr << "Usage: " << argv[0] << " [ input-file [ output-file ] ]" << endl;
exit( -1 ); // TERMINATE!
}
processOneFile (*infile, *outfile, fileList);
// do something
if ( infile != &cin ) delete infile; // close file, do not delete cin!
if ( outfile != &cout ) delete outfile; // close file, do not delete cout!
}
Could you post the original code? The code you posted doesn't even compile.
Errors I've noticed, in order:
processOneFile (*infile, *outfile, fileList);
There is no processOneFile() procedure.
istream *infile = &cin; // default value
ostream *outfile = &cout; // default value
Node* fileList;
case 1: // use cin and cout
break;
processOneFile (*infile, *outfile, fileList);
This will call processOneFile() with an uninitialized file list, which will crash when you try to print the file name.
else {
Node aFile = {argv[1], 0};
fileList = &aFile;
cout << "in main: " << fileList->fileName << endl;
}
aFile is only in scope within that else, so trying to use a pointer to it later will fail.
string getFileName(string oneLine) {
///
return NULL;
}
You can't construct a std::string from NULL -- this will crash the program.
After fixing these errors so your code wouldn't crash, I couldn't reproduce the error.
If you're building in Linux, try increasing the warning level (with g++ -Wall -Wextra -ansi -pedantic) and running your code through valgrind, to check for memory errors.
Ok, the code does now seem like it works as expected:
#include <iostream>
#include <fstream>
using namespace::std;
struct Node
{
string fileName;
Node *link;
};
bool contains (Node *&flist, string &name)
{
Node *tempNode = *&flist;
while (tempNode != 0)
{
cout << "Searching in \"" << flist->fileName;
cout << "\" for \"" << name << "\"" << endl;
if ( tempNode->fileName == name)
{
return true;
}
else
{
tempNode = tempNode->link;
}
}
return false;
}
Node* getLastNode (Node *&flist)
{
Node *tempNode = *&flist;
while (tempNode != 0)
{
tempNode = tempNode->link;
}
return tempNode;
}
string getFileName(string oneLine)
{
char doubleQuote;
doubleQuote = oneLine[9];
if (doubleQuote == '\"') {
string sub = oneLine.substr(10); //getting the file name
string::size_type n = sub.size();
sub = sub.substr(0,n-1);
return sub;
}
return "";
}
void process( istream &in, ostream &out, Node *&flist )
{
cout << "Start of process: " << flist->fileName << endl << endl;
string oneLine;
while (1)
{
cout << "Input include statement: ";
getline(in, oneLine);
if (oneLine == "STOP")
return;
string::size_type loc = oneLine.find("#include",0);
if (loc != string::npos)
{
//found one line starting with "#include"
string name;
name = getFileName(oneLine);
if (name == "")
{
cout << "Couldn't find filename, skipping line..." << endl;
continue;
}
if (contains(flist, name))
{
//contains recursive include
cerr << "Uh, oh! Recursive include of file " << name << endl;
exit(-1);
}
else
{
cerr << "No recursive include" << endl;
}
}//if
cout << endl;
}//while
}
int main( int argc, char *argv[] )
{
Node* fileList = new Node;
istream *infile = &cin; // default value
ostream *outfile = &cout; // default value
fileList->fileName = "Input"; // default value
switch ( argc )
{
case 3:
outfile = new ofstream( argv[2] ); // open the outfile file
if ( outfile->fail() ) {
cerr << "Can't open output file " << argv[2] << endl;
exit( -1 );
}
// FALL THROUGH to handle input file
case 2:
infile = new ifstream( argv[1] ); // open the input file
if ( infile->fail() ) {
cerr << "Can't open input file " << argv[1] << endl;
exit( -1 );
}
else {
fileList->fileName = argv[1];
cout << "in main: " << fileList->fileName << endl;
}
// FALL THROUGH
case 1: // use cin and cout
break;
default: // too many arguments
cerr << "Usage: " << argv[0] << " [ input-file [ output-file ] ]" << endl;
exit( -1 ); // TERMINATE!
}
process(*infile, *outfile, fileList);
// do something
if ( infile != &cin ) delete infile; // close file, do not delete cin!
if ( outfile != &cout ) delete outfile; // close file, do not delete cout!
}
Also, why are you wasting time writing your own linked list when the standard library already has a perfectly good one?