So, I've been trying to get a better understand of how condition variables work and I've written the following code that tries to implement reading and writing from the same text file:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <condition_variable>
#include <mutex>
#include <thread>
using namespace std;
mutex mtx;
condition_variable conditionVariable;
ifstream readFile;
ofstream writeFile;
bool doneReading=false;
bool doneWriting=false;
void readFromFile()
{
string line;
readFile.open("./testFile.txt");
if(readFile.is_open())
{
cout << "Successfully opened file!" << "\n";
}
else
{
cout << "Failed to open file..." << "\n";
}
cout << "The file contents are:" << "\n";
while(getline(readFile,line))
{
unique_lock<mutex> lock(mtx);
conditionVariable.wait(lock, [] () {return doneWriting;});
cout << line << "\n";
doneReading=true;
lock.unlock();
conditionVariable.notify_one();
}
readFile.close();
}
void writeToFile()
{
string input;
writeFile.open("./testFile.txt");
cout << "Enter something you want to write to the text file:" << "\n";
cin >> input;
cout << "Going to write " << input << " to the file" << "\n";
if(writeFile.is_open())
{
cout << "Successfully opened file!" << "\n";
unique_lock<mutex> lock2(mtx);
/////////PROGRAM WON'T ADVANCE PAST THIS LINE/////////////
conditionVariable.wait(lock2, [] () {return doneReading;});
cout << "After calling the wait function for the condition variable" << "\n";
writeFile << input;
doneWriting=true;
lock2.unlock();
conditionVariable.notify_one();
writeFile.close();
}
else
{
cout << "Failed to open file..." << "\n";
}
}
int main()
{
int i;
for(i=0;i<10;i++)
{
thread t1(readFromFile);
thread t2(writeToFile);
t1.join();
t2.join();
}
}
And, I modeled my use of boolean variables after the following example from
cppreference.com (scroll down to the bottom to see the example code). However, it has something do the predicate I am passing to the wait function, and I'm not quite sure what is wrong with it. If someone could give some insight, that would be brilliant. Thanks!
Initial state is:
bool doneReading=false;
bool doneWriting=false;
The first thing readFromFile does to these variables is sit and wait for doneWriting to become true
conditionVariable.wait(lock, [] () {return doneWriting;});
The first thing writeFromFile does to these variables is sit and wait for doneReading to become true
conditionVariable.wait(lock2, [] () {return doneReading;});
Neither condition will become true.
Note that the cppreference example does something very different: one thread begins by executing cv.wait(lk, []{return ready;}); while the other begins by executing ready=true;
Related
So I have the following code:
#include <iostream>
#include <fstream>
#include <string>
void writeSingle(std::fstream &myFileStream)
{
myFileStream.open("my_file2", std::ios::trunc);
if (!myFileStream)
{
std::cout << "File not created!\n";
}
else
{
std::cout << "File created successfully!\n";
myFileStream << "Line 1\n";
myFileStream << "Line 2\n";
myFileStream << "Line 3\n";
myFileStream.close();
}
}
int main()
{
std::fstream myFileStream;
writeSingle(myFileStream);
return 0;
}
My question is, whenever I use std::ios::trunc, be it in a combination with app (std::ios::trunc | std::ios::app) and regardless to whether the file exists or not, the program
ends up in the !myFileStream block. With only std::ios::out and std::ios::app the program works as expected.
Why is it so? Can someone provide at least one working example with std::ios::trunc?
Thanks.
C++98 and Boost 1.54
I'm having trouble figuring out why using boost::this_thread::sleep_for is sleeping my entire program. The only time and place the Wait() function is called is inside this thread, and this thread's sole purpose is to read file names in a directory and trigger an upload.
But for some reason, when it reaches the boost::this_thread::sleep_for line in the Wait() function, it hangs there and sleeps all the other threads as well. I'm unsure what I am missing, so any help would be appreciated.
Code:
void Upload::ReadFileNames()
{
cout << "[DEBUG] ReadFileNames -> A " << endl;
Wait();
cout << "[DEBUG] ReadFileNames -> B " << endl;
// read filename stuff
}
void Upload::Wait()
{
typedef boost::chrono::duration<long, boost::ratio<60> > seconds;
int randomWaitTime = 0;
try{
randomWaitTime = lexical_cast<unsigned int>(getId());
randomWaitTime = randomWaitTime * 10;
}
catch ( const boost::bad_lexical_cast & e){
// cout << "[LOG] FileUpLoad : Wait : bad_lexical_cast : " << e.what() << endl ;
randomWaitTime = 0;
}
seconds testTimeToWait(randomWaitTime);
cout << "[DEBUG] Wait() -> A" << endl;
boost::this_thread::sleep_for(testTimeToWait);
cout << "[DEBUG] Wait() -> B" << endl;
cout << "RANDOM WAIT TIME = " << randomWaitTime << endl;
}
main.cpp
int main()
{
pthread_t threadA;
pthread_create(&threadA,NULL,threadAfn,NULL);
pthread_t threadB;
pthread_create(&threadB,NULL,threadBfn,NULL);
pthread_t Upload; // <--- Thread in question
pthread_create(&Upload,NULL,Uploadfn,NULL);
pthread_join(threadA,NULL);
pthread_join(threadB,NULL);
pthread_join(Upload,NULL); // <--- Thread in question
return 0;
}
Output
[DEBUG] ReadFileNames -> A
[DEBUG] Wait() -> A
// hangs here and rest of the threads are locked/slept as well?
it hangs there and sleeps all the other threads as well
No it doesn't. If it seems that way, that is because the other threads were already stuck or finished.
Look for things that block (mutex.lock, condition wait, IO operations, etc.) or check that the threads didn't exit.
Notes
Your seconds calculations is off. On my system, the following:
Live On Coliru
#include <boost/chrono.hpp>
#include <iostream>
int main() {
std::cout << boost::chrono::duration<long, boost::ratio<60> >(1)/boost::chrono::seconds(1) << std::endl;
}
Prints
60
So, what you named seconds is actually minutes. Just do this instead:
using boost::chrono::seconds;
int delay = std::strtoul(getId().c_str(), NULL, 10)*10;
sleep_for(seconds(delay));
Your random delay is only random if the getId return is. Using boost/random.hpp you can make it truly random, with good range control. E.g. to sleep between 1'000 and 3'000 ms:
int random_gen(int low, int high) { // not threadsafe
static boost::random_device rdev;
static boost::mt19937 prng(rdev);
return boost::uniform_int<>(low, high)(prng);
}
void Upload::Wait() {
int const ms_delay = random_gen(1000, 3000);
cout << "RANDOM WAIT TIME = " << ms_delay << endl;
sleep_for(milliseconds(ms_delay));
}
Note to seed using random_device as shown (so true random seed) you need to link the random library. Otherwise, you can "stoop" to a time-based seed:
static boost::mt19937 prng(std::time(NULL));
Here's a self-contained version of your code with the various suggestions applied, demonstrating that there is no deadlock/softlock:
Live On Coliru
#include <boost/asio.hpp>
#include <boost/chrono.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>
#include <iostream>
#include <boost/random.hpp>
using boost::this_thread::sleep_for;
using boost::chrono::seconds;
using boost::chrono::milliseconds;
using boost::lexical_cast;
using std::cout;
using std::endl;
struct Upload {
std::string getId() const { return "42"; }
void Wait();
void ReadFileNames();
};
void Upload::ReadFileNames() {
cout << "[DEBUG] ReadFileNames -> A " << endl;
Wait();
cout << "[DEBUG] ReadFileNames -> B " << endl;
// read filename stuff
}
int random_gen(int low, int high) { // not threadsafe
static boost::mt19937 prng(std::time(NULL));
return boost::uniform_int<>(low, high)(prng);
}
void Upload::Wait() {
int const ms_delay = random_gen(1000, 3000);
cout << "RANDOM WAIT TIME = " << ms_delay << endl;
sleep_for(milliseconds(ms_delay));
}
void background(char const* name) {
// desync different background threads
sleep_for(milliseconds(boost::hash_value(name) % 1000));
for (int i=0; i<5; ++i) {
sleep_for(seconds(1));
std::clog << name << " " << i << std::endl;
}
}
void threadAfn() { background("thread A"); }
void threadBfn() { background("thread B"); }
void Uploadfn() {
Upload u;
u.ReadFileNames();
}
int main() {
boost::thread threadA(threadAfn);
boost::thread threadB(threadBfn);
boost::thread Upload(Uploadfn);
threadA.join();
threadB.join();
Upload.join();
}
Prints, e.g.:
[DEBUG] ReadFileNames -> A
RANDOM WAIT TIME = 1150
[DEBUG] ReadFileNames -> B
thread A 0
thread B 0
thread A 1
thread B 1
thread A 2
thread B 2
thread A 3
thread B 3
thread A 4
thread B 4
I have a main program, this main program executes a thread that perform an action until the user triggers a stop. The problem that I have is if I add th.join() the main program won't continue until the thread finishes. And If there is no .join() the program crashs.
#include <iostream>
#include <thread>
#include <optional>
static bool s_finished = false;
using namespace std::literals::chrono_literals;
void SendData(int id)
{
std::cout << "Working thread: " << id << std::endl;
std::cout << "Started thread id: " << std::this_thread::get_id() << std::endl;
while (!s_finished)
{
std::cout << "Working\n";
std::this_thread::sleep_for(1s);
}
}
void startRecording(std::optional<int> t)
{
std::thread th1 (SendData, 1);
//th1.join();
std::cout << "[startRecording] Other Task" << std::endl;
}
void stopRecording()
{
s_finished = true;
std::cout << "[stopRecording] Other Task" << std::endl;
}
int main()
{
std::cout << "Start Program!" << std::endl;
startRecording();
std::this_thread::sleep_for(5s);
stopRecording();
return 0;
}
How can I do this?
Joining a thread will cause the program to stop until that thread is finished, and that's why the program blocks. We have to call join() eventually so that all child threads finish before the program exits, but we shouldn't call join until we need the child thread to be finished.
The simplest way to get the program to work is to return the thread from startRecording, so that we have control of it inside main. Then, we join the thread at the end of main, after we call stopRecording.
#include <iostream>
#include <thread>
#include <optional>
#include <atomic>
// (1) This needs to be atomic to avoid data races
std::atomic<bool> s_finished { false };
using namespace std::literals::chrono_literals;
void SendData(int id)
{
std::cout << "Working thread: " << id << std::endl;
std::cout << "Started thread id: " << std::this_thread::get_id() << std::endl;
while (!s_finished)
{
std::cout << "Working\n";
std::this_thread::sleep_for(1s);
}
}
std::thread startRecording(std::optional<int> t)
{
std::thread th1 (SendData, 1);
std::cout << "[startRecording] Other Task" << std::endl;
// (2) We return the thread so we can join it in main:
return th1;
}
void stopRecording()
{
s_finished = true;
std::cout << "[stopRecording] Other Task" << std::endl;
}
int main()
{
std::cout << "Start Program!" << std::endl;
// (3) We save the thread to a variable named 'worker'
// so we can join it later. I also added an input to startRecording b/c it needed one
std::thread worker = startRecording(std::optional<int>{1});
std::this_thread::sleep_for(5s);
stopRecording();
// (4) Join here, at the end
worker.join();
return 0;
}
Now, the program prints the expected output, then exits without problems:
Start Program!
[startRecording] Other Task
Working thread: 1
Started thread id: 139985258444544
Working
Working
Working
Working
Working
[stopRecording] Other Task
I marked my changes with (1), (2), (3), and (4) in the comments of the code. They're pretty small, and if you have questions about any of them I can provide additional explanation!
Addendum - using global variables when the signature of startRecording can't be changed
In general, it's best to avoid global variables, but I know it's not always possible to do so. if startRecording's signature can't be changed, we can't return a thread, so the thread has to be accessed globally. Here's how to do that:
#include <iostream>
#include <thread>
#include <optional>
#include <atomic>
// (1) This needs to be atomic to avoid data races
std::atomic<bool> s_finished { false };
// (2) we initialize this in startRecording
std::thread worker;
using namespace std::literals::chrono_literals;
void SendData(int id)
{
std::cout << "Working thread: " << id << std::endl;
std::cout << "Started thread id: " << std::this_thread::get_id() << std::endl;
while (!s_finished)
{
std::cout << "Working\n";
std::this_thread::sleep_for(1s);
}
}
void startRecording(std::optional<int> t)
{
// (3) worker gets initialized, and thread starts
worker = std::thread(SendData, 1);
std::cout << "[startRecording] Other Task" << std::endl;
}
void stopRecording()
{
s_finished = true;
std::cout << "[stopRecording] Other Task" << std::endl;
}
int main()
{
std::cout << "Start Program!" << std::endl;
startRecording(std::optional<int>{1});
std::this_thread::sleep_for(5s);
stopRecording();
// (4) Join here, at the end
worker.join();
return 0;
}
How can i make a small program that prints something endlessly, but I can still use the standard input to write and display something whenever I want?
I found this example, but it terminates after just 2 inputs (and I want to input something multiple times, not just 2).
#include <iostream>
#include <thread>
#include <chrono>
#include <string>
using std::cout;
using std::cin;
using std::thread;
using std::string;
using std::endl;
int stopflag = 0;
void input_func()
{
while (true && !stopflag)
{
string input;
cin >> input;
cout << "Input: " << input << endl;
}
}
void output_func()
{
while (true && !stopflag)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
cout << "Output thread\n";
}
}
int main()
{
while (1)
{
thread inp(input_func);
thread outp(output_func);
std::this_thread::sleep_for(std::chrono::seconds(5));
stopflag = 1;
outp.join();
cout << "Joined output thread\n";
inp.join();
}
cout << "End of main, all threads joined.\n";
return 0;
}
Just remove the line stopflag = 1. But also, if you want to print the lines you need to add synchronization to modify flag and also printing. Because only one thread should write to console and one time. Don't forget to add flush, as it will not print all text always.
I have the book "beyond the C++ standard library" and there are no examples of multithreading using boost. Would somebody be kind enough to show me a simple example where two threads are executed using boost- lets say asynchronously?
This is my minimal Boost threading example.
#include <boost/thread.hpp>
#include <iostream>
using namespace std;
void ThreadFunction()
{
int counter = 0;
for(;;)
{
cout << "thread iteration " << ++counter << " Press Enter to stop" << endl;
try
{
// Sleep and check for interrupt.
// To check for interrupt without sleep,
// use boost::this_thread::interruption_point()
// which also throws boost::thread_interrupted
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
}
catch(boost::thread_interrupted&)
{
cout << "Thread is stopped" << endl;
return;
}
}
}
int main()
{
// Start thread
boost::thread t(&ThreadFunction);
// Wait for Enter
char ch;
cin.get(ch);
// Ask thread to stop
t.interrupt();
// Join - wait when thread actually exits
t.join();
cout << "main: thread ended" << endl;
return 0;
}