Are I/O streams really thread-safe? - c++

I wrote a program that writes random numbers to one file in the first thread, and another thread reads them from there and writes to another file those that are prime numbers. The third thread is needed to stop/start the work. I read that I/O threads are thread-safe. Since writing to a single shared resource is thread-safe, what could be the problem?
Output: always correct record in numbers.log, sometimes no record in numbers_prime.log when there are prime numbers, sometimes they are all written.
#include <iostream>
#include <fstream>
#include <thread>
#include <mutex>
#include <vector>
#include <condition_variable>
#include <future>
#include <random>
#include <chrono>
#include <string>
using namespace std::chrono_literals;
std::atomic_int ITER_NUMBERS = 30;
std::atomic_bool _var = false;
bool ret() { return _var; }
std::atomic_bool _var_log = false;
bool ret_log() { return _var_log; }
std::condition_variable cv;
std::condition_variable cv_log;
std::mutex mtx;
std::mutex mt;
std::atomic<int> count{0};
std::atomic<bool> _FL = 1;
int MIN = 100;
int MAX = 200;
bool is_empty(std::ifstream& pFile) // function that checks if the file is empty
{
return pFile.peek() == std::ifstream::traits_type::eof();
}
bool isPrime(int n) // function that checks if the number is prime
{
if (n <= 1)
return false;
for (int i = 2; i <= sqrt(n); i++)
if (n % i == 0)
return false;
return true;
}
void Log(int min, int max) { // function that generates random numbers and writes them to a file numbers.log
std::string str;
std::ofstream log;
std::random_device seed;
std::mt19937 gen{seed()};
std::uniform_int_distribution dist{min, max};
log.open("numbers.log", std::ios_base::trunc);
for (int i = 0; i < ITER_NUMBERS; ++i, ++count) {
std::unique_lock<std::mutex> ulm(mtx);
cv.wait(ulm,ret);
str = std::to_string(dist(gen)) + '\n';
log.write(str.c_str(), str.length());
log.flush();
_var_log = true;
cv_log.notify_one();
//_var_log = false;
//std::this_thread::sleep_for(std::chrono::microseconds(500000));
}
log.close();
_var_log = true;
cv_log.notify_one();
_FL = 0;
}
void printCheck() { // Checking function to start/stop printing
std::cout << "Log to file? [y/n]\n";
while (_FL) {
char input;
std::cin >> input;
std::cin.clear();
if (input == 'y') {
_var = true;
cv.notify_one();
}
if (input == 'n') {
_var = false;
}
}
}
void primeLog() { // a function that reads files from numbers.log and writes prime numbers to numbers_prime.log
std::unique_lock ul(mt);
int number = 0;
std::ifstream in("numbers.log");
std::ofstream out("numbers_prime.log", std::ios_base::trunc);
if (is_empty(in)) {
cv_log.wait(ul, ret_log);
}
int oldCount{};
for (int i = 0; i < ITER_NUMBERS; ++i) {
if (oldCount == count && count != ITER_NUMBERS) { // check if primeLog is faster than Log. If it is faster, then we wait to continue
cv_log.wait(ul, ret_log);
_var_log = false;
}
if (!in.eof()) {
in >> number;
if (isPrime(number)) {
out << number;
out << "\n";
}
oldCount = count;
}
}
}
int main() {
std::thread t1(printCheck);
std::thread t2(Log, MIN, MAX);
std::thread t3(primeLog);
t1.join();
t2.join();
t3.join();
return 0;
}

This has nothing to do with the I/O stream thread safety. The shown code's logic is broken.
The shown code seems to follow a design pattern of breaking up a single logical algorithm into multiple pieces, and scattering them far and wide. This makes it more difficult to understand what it's doing. So let's rewrite a little bit of it, to make the logic more clear. In primeLog let's do this instead:
cv_log.wait(ul, []{ return _var_log; });
_var_log = false;
It's now more clear that this waits for _var_log to be set, before proceeding on its merry way. Once it is it gets immediately reset.
The code that follows reads exactly one number from the file, before looping back here. So, primeLog's main loop will always handle exactly one number, on each iteration of the loop.
The problem now is very easy to see, once we head over to the other side, and do the same clarification:
std::unique_lock<std::mutex> ulm(mtx);
cv.wait(ulm,[]){ return _var; });
// Code that generates one number and writes it to the file
_var_log = true;
cv_log.notify_one();
Once _var is set to true, it remains true. This loops starts running full blast, iterating continuously. On each iteration of the loop it blindly sets _var_log to true and signals the other thread's condition variable.
C++ execution threads are completely independent of each other unless they are explicitly synchronize in some way.
Nothing is preventing this loop from running full blast, getting through its entire number range, before the other execution thread wakes up and decides to read the first number from the file. It'll do that, then go back and wait for its condition variable to be signaled again, for the next number. Its hopes and dreams of the 2nd number will be left unsatisfied.
On each iteration of the generating thread's loop the condition variable, for the other execution thread, gets signaled.
Condition variables are not semaphores. If nothing is waiting on a condition variable when it's signaled -- too bad. When some execution thread decides to wait on a condition variable, it may or may not be immediately woken up.
One of these two execution thread relies on it receiving a condition variable notification for every iteration of its loop.
The logic in the other execution thread fails to implement this guarantee. This may not be the only flaw, there might be others, subject to further analysis, this was just the most apparent logical flaw.

Thanks to those who wrote about read-behind-write, now I know more. But that was not the problem. The main problem was that if it was a new file, when calling pFile.peek() in the is_empty function, we permanently set the file flag to eofbit. Thus, until the end of the program in.rdstate() == std::ios_base::eofbit.
Fix: reset the flag state.
if (is_empty(in)) {
cv_log.wait(ul, ret_log);
}
in.clear(); // reset state
There was also a problem with the peculiarity of reading/writing one file from different threads, though it was not the cause of my program error, but it led to another one.
Because if when I run the program again primeLog() opens std::ifstream in("numbers.log") for reading faster than log.open("numbers.log", std::ios_base::trunc), then in will save old data into its buffer faster than log.open will erase them with the std::ios_base::trunc flag. Hence we will read and write to numbers_prime.log the old data.

Related

Why it doesn't work? Simple multithreading example

can you help me with understanding why does this code freeze the program?
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
int i = 0;
mutex mx;
void foo() {
while(1) {
lock_guard<mutex> locker(mx);
i++;
if(i == 5000) {
break;
}
}
}
void boo() {
while(1) {
if(i == 100) {
lock_guard<mutex> locker(mx);
i = 5000;
break;
}
}
}
int main(int argc, char *argv[])
{
thread th1(foo);
thread th2(boo);
th1.join();
th2.join();
return 0;
}
Why do I have such a result?
How to change the code to make it right? Could you give me your thoughts.
Thanks.
Even if boo starts running first, it will probably never see i==100.
If you only have one CPU, then it's very unlikely that the CPU would be switched from foo to boo while i==100.
If you have multiple CPUs, then i==100 will probably never even make it into foo's cache, because i is not volatile, and the mutex is not locked between reads.
Really the compiler doesn't even have to read i after the first time, because there are no memory barriers. It can assume that the value hasn't changed.
Even if you were to fix this, the distinct possibility would remain that i could be incremented past 100 before boo would notice. It looks like you expect the two threads to "take turns", but that's just not how it works.
The behavior of the program is undefined, so reasoning about what it does is futile. The problem is that boo reads the value of i and foo both reads and writes the value of i, but the read of i in if (i == 100) in boo is unsequenced with respect to the writes occurring in foo. That's a data race, and the behavior of the program is undefined. Sure, you can guess at what might happen, but if you want your code to run correctly, you have to ensure that there are no data races. That means using some form of synchronization: either move the lock in boo before the if, or get rid of the mutex and change the type of i to std::atomic<int>.
There are a few concurrency issues with your solution:
You have to lock the mutex consistently. All access to i must be protected by the mutex, so also at the if (i == 100) { line. In the absence of synchronization, the compiler is free to optimize the thread as-if it was running in isolation, and assume i to never change.
There is no guarantee that boo will start before foo. If it starts after, i will already be incremented well above 100.
Mutex locking is not guaranteed to be fair. Two threads competing for the same mutex will not run in an interleaved manner. Which means foo might increment i many times before boo gets a chance to run, so the value of i as seen by boo might easily jump from 0 to 1000, skipping the desired 100.
In isolation, foo will "run away", incrementing i well beyond 5000. There should be some exit or a restart condition.
How to change the code to make it right?
Add some synchronization in order to enforce interleaved processing. For example, using condition_variables to signal between threads:
int i = 0;
mutex mx;
condition_variable updated_cond;
bool updated = false;
condition_variable consumed_cond;
bool consumed = true;
void foo() {
while (1) {
unique_lock<mutex> locker(mx);
consumed_cond.wait(locker, [] { return consumed; });
consumed = false;
if (i == 5000) {
break;
}
std::cout << "foo: i = " << i << "+1\n";
i++;
updated = true;
updated_cond.notify_one();
}
std::cout << "foo exiting\n";
}
void boo() {
for (bool exit = false; !exit; ) {
unique_lock<mutex> locker(mx);
updated_cond.wait(locker, [] { return updated; });
updated = false;
std::cout << "boo: i = " << i << "\n";
if (i == 100) {
i = 5000;
exit = true;
}
consumed = true;
consumed_cond.notify_one();
}
std::cout << "boo exiting\n";
}

How to multithread reading a file in c++11?

I have a big file, and i have to read it by chunk. Each time when i read a chunk, i have to do some time consuming operation, so i think multithread reading might help, each thread reads a chunk one by one and does its operation. here is my code in c++11
#include<iostream>
#include<fstream>
#include <condition_variable>
#include <mutex>
#include <thread>
using namespace std;
const int CHAR_PER_FILE = 1e8;
const int NUM_THREAD = 2;
int order = -1;
bool is_reading = false;
mutex mtx;
condition_variable file_not_reading;
void partition(ifstream& is)
{
while (is.peek() != EOF)
{
unique_lock<mutex> lock(mtx);
while (is_reading)
file_not_reading.wait(lock);
is_reading = true;
char *c = new char[CHAR_PER_FILE];
is.read(c, CHAR_PER_FILE);
order++;
is_reading = false;
file_not_reading.notify_all();
lock.unlock();
char oc[3];
sprintf(oc, "%d", order);
this_thread::sleep_for(chrono::milliseconds(2000));//some operations that take long time
ofstream os(oc, ios::binary);
os.write(c, CHAR_PER_FILE);
delete[] c;
os.close();
}
}
int main()
{
ifstream is("bigfile.txt",ios::binary);
thread threads[NUM_THREAD];
for (int i = 0; i < NUM_THREAD; i++)
threads[i] = thread(partition, ref(is));
for (int i = 0; i < NUM_THREAD; i++)
threads[i].join();
is.close();
system("pause");
return 0;
}
But my code didn't work, it only created 4 files instead of `bigfilesize/CHAR_PER_FILE, and threads seem got stuck, how can i make it work?
Is there any c++11 multithread reading file implementation or example?
Thanks.
My advice:
Use one thread to read chunks from the file. Every time a chunk is read, post it to a request queue. It is not worth reading multithreaded as there will be internal locks/blocking reading a common resource.
Use a pool of threads. Each of them read from the queue, retrieves a chunk, execute the expensive operation and go back to wait for a new request.
The queue must be mutex protected.
Don't use more threads than the number of processing units (CPU/Cores/HyperThreads) you have.
The main caveat of the above is that it will not guarantee the processing order. You will probably need to post the results to a central place that can reorder (again central place -> must be mutex protected).
You could use task-based parallelism with std::async:
class result; // result of expensive operation
result expensive_operation(std::vector<char> const& data)
{
result r = // long computation
return r;
}
std::vector<char>::size_type BLOCK_SIZE = 4096;
std::vector<std::future<result>> partition(ifstream& in)
{
std::vector<std::future<result>> tasks;
while (!in.eof() && !in.fail())
{
std::vector<char> c(BLOCK_SIZE);
is.read(c.data(), BLOCK_SIZE);
c.resize(in.gcount());
tasks.push_back( std::async( [](std::vector<char> data)
{
return expensive_operation(data);
},
std::move(c) ));
}
return tasks;
}
int main()
{
ifstream is("bigfile.txt",ios::binary);
auto results = partition(is);
// iterate over results and do something with it
}
Does the file have to be read in "sequential" order, i.e. do the chunks have to be "operated" on in a special order? Otherwise you could e.g. make 4 threads and let each thread read 1/4 of the file (you could do this by using tellg and saving the position in e.g. a vector or variable). That way you wouldn't have to use locks.
Maybe you could tell us how the data you read in has to be evaluated.
Perhaps...
void partition(ifstream& is)
{
unique_lock<mutex> lock(mtx);
std::vector<char> c(CHAR_PER_FILE);
is.read(c.data(), CHAR_PER_FILE);
lock.unlock();
if (is.fail() && !is.eof()) return;
size_t num_bytes_read = is.gcount();
std::ostringstream oc;
oc << order;
this_thread::sleep_for(chrono::milliseconds(2000)); //take long time
if (std::ofstream os(oc, ios::binary))
os.write(c.data(), CHAR_PER_FILE);
}
Notes:
The mutex serialises the operations already - no need for a condition variable.
I've added a little input error and bytes-read handling - you should check after os.write() too, add an else for failed ofstream creation etc.

C++11 thread to modify std::list

I'll post my code, and then tell you what I think it's doing.
#include <thread>
#include <mutex>
#include <list>
#include <iostream>
using namespace std;
...
//List of threads and ints
list<thread> threads;
list<int> intList;
//Whether or not a thread is running
bool running(false);
//Counters
int busy(0), counter(0);
//Add 10000 elements to the list
for (int i = 0; i < 10000; ++i){
//push back an int
intList.push_back(i);
counter++;
//If the thread is running, make a note of it and continue
if (running){
busy++;
continue;
}
//If we haven't yet added 10 elements before a reset, continue
if (counter < 10)
continue;
//If we've added more than 10 ints, and there's no active thread,
//reset the counter and launch
counter = 0;
threads.push_back(std::thread([&]
//These iterators are function args
(list<int>::iterator begin, list<int>::iterator end){
//mutex for the running bool
mutex m;
m.lock();
running = true;
m.unlock();
//Remove either 10 elements or every element till the end
int removed(0);
while (removed < 10 && begin != end){
begin = intList.erase(begin);
removed++;
}
//unlock the running bool
m.lock();
running = false;
m.unlock();
//Pass into the thread func the current beginning and end of the list
}, intList.begin(), intList.end()));
}
for (auto& thread : threads){
thread.join();
}
What I think this code is doing is adding 10000 elements to the end of a list. For every 10 we add, launch a (single) thread that deletes the first 10 elements of the list (at the time the thread was launched).
I don't expect this to remove every list element, I was just interested in seeing if I could add to the end of a list while removing elements from the beginning. In Visual Studio I get a "list iterators incompatible" error quite often, but I figure the problem is cross platform.
What's wrong with my thinking? I know it's something
EDIT:
So I see now that this code is very incorrect. Really I just want one auxiliary thread active at a time to delete elements, which is why I though calling erase was ok. However I don't know how to declare a thread without joining it up, and if I wait for that then I don't really see the point of doing any of this.
Should I declare my thread before the loop and have it wait for a signal from the main thread?
To clarify, my goal here is to do the following: I want to grab keyboard presses on one thread and store them in a list, and every so often log them to a file on a separate thread while removing the things I've logged. Since I don't want to spend a lot of time writing to the disk, I'd like to write in discrete chunks (of 10).
Thanks to Christophe, and everyone else. Here's my code now... I may be using lock_guard incorrectly.
#include <thread>
#include <mutex>
#include <list>
#include <iostream>
#include <atomic>
using namespace std;
...
atomic<bool> running(false);
list<int> intList;
int busy(0), counter(0);
mutex m;
thread * t(nullptr);
for (int i = 0; i < 100000; ++i){
//Would a lock_guard here be inappropriate?
m.lock();
intList.push_back(i);
m.unlock();
counter++;
if (running){
busy++;
continue;
}
if (counter < 10)
continue;
counter = 0;
if (t){
t->join();
delete t;
}
t = new thread([&](){
running = true;
int removed(0);
while (removed < 10){
lock_guard<mutex> lock(m);
if (intList.size())
intList.erase(intList.begin());
removed++;
}
running = false;
});
}
if (t){
t->join();
delete t;
}
Your code won't work for because:
your mutex is local to each thread (each thread has it's own copy used only by itself: no chance of interthread synchronisation!)
intList is not an atomic type, but you access to it from several threads causing race conditions and undefined behaviour.
the begin and end that you send to your threads at their creation, might no longer be valid during the execution.
Here some improvements (look at the commented lines):
atomic<bool> running(false); // <=== atomic (to avoid unnecessary use of mutex)
int busy(0), counter(0);
mutex l; // define the mutex here, so that it will be the same for all threads
for (int i = 0; i < 10000; ++i){
l.lock(); // <===you need to protect each access to the list
intList.push_back(i);
l.unlock(); // <===and unlock
counter++;
if (running){
busy++;
continue;
}
if (counter < 10)
continue;
counter = 0;
threads.push_back(std::thread([&]
(){ //<====No iterator args as they might be outdated during executionof threads!!
running = true; // <=== no longer surrounded from lock/unlock as it is now atomic
int removed(0);
while (removed < 10){
l.lock(); // <====you really need to protect access to the list
if (intList.size()) // <=== check if elements exist NOW
intList.erase(intList.begin()); // <===use current data, not a prehistoric outdated local begin !!
l.unlock(); // <====end of protected section
removed++;
}
running = false; // <=== no longer surrounded from lock/unlock as it is now atomic
})); //<===No other arguments
}
...
By the way, I'd suggest that you have a look at lock_guard<mutex> for the locks, as these ensure the unlock in all circumstances (especially when there are exceptions or orhter surprises like this).
Edit: I've avoided the lock protection of running with a mutex, by making it atomic<bool>.

Threading in c++

Lets say I want to take an input from user and perform a search in a text file for that input. The search will be performed for every character user inputs. There will be a loop performing search and there will be another loop to check if new character is input by the user. Second loop will restart the first loop if new char is given by the user.
Please just explain how to perform above with c++. I think threads need to be created.
Below variables will be used to maintain common values:
static var`
bool change;
while(!change)
{
change=false
<<do something, like search in file>>
}
Other loop will be like below:
while(1)
{
if(user enters another char)
{
var=new value input by the user;
change=true;
}
else change=false;
}
Thanks!
Something like this? Now I wrote this on ideone and their threads didn't work for me so I wasn't able to test it but yeah.. Something close to this should work. Probably a bad example. A thread pool would be best.
#include <iostream>
#include <thread>
#include <atomic>
#include <queue>
#include <mutex>
#include <chrono>
std::mutex lock;
std::atomic<bool> stop(false);
std::queue<std::function<void()>> jobs;
void One()
{
while(!stop)
{
if (!jobs.empty())
{
if (lock.try_lock())
{
std::function<void()> job = jobs.front();
jobs.pop();
lock.unlock();
job();
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
void Two()
{
std::string var;
while(true)
{
if (std::cin>> var)
{
std::lock_guard<std::mutex> glock(lock);
jobs.push([] {std::cout<<"Task added to the queue..\n";});
}
else
break;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
int main()
{
std::thread T(One);
Two();
stop = true;
T.join();
return 0;
}
Create two threads: one for reading user-input, and another for performing the search.
Use a binary-semaphore in order to synchronize between the two threads in a Consumer-Producer manner, i.e., one thread acquires the semaphore and the other thread releases it:
static BinarySemaphore binSem;
static int inputCharacter = 0;
static void ReadUserInput();
static void PerformSearch();
void Run()
{
BinarySemaphore_Init(&binSem,0);
CreateThread(ReadUserInput,LOWER_PRIORITY);
CreateThread(PerformSearch,HIGHER_PRIORITY);
}
static void ReadUserInput()
{
while (inputCharacter != '\n')
{
inputCharacter = getc(stdin);
BinarySemaphore_Set(&binSem);
}
}
static void PerformSearch()
{
while (inputCharacter != '\n')
{
BinarySemaphore_Get(&binSem,WAIT_FOREVER);
// <<do something, like search in file>>
}
}
Please note that you need to create the thread which performs the search, with priority higher than that of the thread which reads user-input (as in the code above).

Stop infinite looping thread from main

I am relatively new to threads, and I'm still learning best techniques and the C++11 thread library. Right now I'm in the middle of implementing a worker thread which infinitely loops, performing some work. Ideally, the main thread would want to stop the loop from time to time to sync with the information that the worker thread is producing, and then start it again. My idea initially was this:
// Code run by worker thread
void thread() {
while(run_) {
// Do lots of work
}
}
// Code run by main thread
void start() {
if ( run_ ) return;
run_ = true;
// Start thread
}
void stop() {
if ( !run_ ) return;
run_ = false;
// Join thread
}
// Somewhere else
volatile bool run_ = false;
I was not completely sure about this so I started researching, and I discovered that volatile is actually not required for synchronization and is in fact generally harmful. Also, I discovered this answer, which describes a process nearly identical to the one I though about. In the answer's comments however, this solution is described as broken, as volatile does not guarantee that different processor cores readily (if ever) communicate changes on the volatile values.
My question is this then: Should I use an atomic flag, or something else entirely? What exactly is the property that is lacking in volatile and that is then provided by whatever construct is needed to solve my problem effectively?
Have you looked for the Mutex ? They're made to lock the Threads avoiding conflicts on the shared data. Is it what you're looking for ?
I think you want to use barrier synchronization using std::mutex?
Also take a look at boost thread, for a relatively high level threading library
Take a look at this code sample from the link:
#include <iostream>
#include <map>
#include <string>
#include <chrono>
#include <thread>
#include <mutex>
std::map<std::string, std::string> g_pages;
std::mutex g_pages_mutex;
void save_page(const std::string &url)
{
// simulate a long page fetch
std::this_thread::sleep_for(std::chrono::seconds(2));
std::string result = "fake content";
g_pages_mutex.lock();
g_pages[url] = result;
g_pages_mutex.unlock();
}
int main()
{
std::thread t1(save_page, "http://foo");
std::thread t2(save_page, "http://bar");
t1.join();
t2.join();
g_pages_mutex.lock(); // not necessary as the threads are joined, but good style
for (const auto &pair : g_pages) {
std::cout << pair.first << " => " << pair.second << '\n';
}
g_pages_mutex.unlock();
}
I would suggest to use std::mutex and std::condition_variable to solve the problem. Here's an example how it can work with C++11:
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
int main()
{
mutex m;
condition_variable cv;
// Tells, if the worker should stop its work
bool done = false;
// Zero means, it can be filled by the worker thread.
// Non-zero means, it can be consumed by the main thread.
int result = 0;
// run worker thread
auto t = thread{ [&]{
auto bound = 1000;
for (;;) // ever
{
auto sum = 0;
for ( auto i = 0; i != bound; ++i )
sum += i;
++bound;
auto lock = unique_lock<mutex>( m );
// wait until we can safely write the result
cv.wait( lock, [&]{ return result == 0; });
// write the result
result = sum;
// wake up the consuming thread
cv.notify_one();
// exit the loop, if flag is set. This must be
// done with mutex protection. Hence this is not
// in the for-condition expression.
if ( done )
break;
}
} };
// the main threads loop
for ( auto i = 0; i != 20; ++i )
{
auto r = 0;
{
// lock the mutex
auto lock = unique_lock<mutex>( m );
// wait until we can safely read the result
cv.wait( lock, [&]{ return result != 0; } );
// read the result
r = result;
// set result to zero so the worker can
// continue to produce new results.
result = 0;
// wake up the producer
cv.notify_one();
// the lock is released here (the end of the scope)
}
// do time consuming io at the side.
cout << r << endl;
}
// tell the worker to stop
{
auto lock = unique_lock<mutex>( m );
result = 0;
done = true;
// again the lock is released here
}
// wait for the worker to finish.
t.join();
cout << "Finished." << endl;
}
You could do the same with std::atomics by essentially implementing spin locks. Spin locks can be slower than mutexes. So I repeat the advise on the boost website:
Do not use spinlocks unless you are certain that you understand the consequences.
I believe that mutexes and condition variables are the way to go in your case.