In this program, I'm trying to print my username and then create two threads. I want each thread to print its thread id and go into a loop and display something periodically.
Here is the code I have
#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
#include <string>
void task(std::string threadNum)
{
std::thread::id this_id = std::this_thread::get_id();
std::cout << threadNum << " : " << this_id << std::endl;
for(int i=0; i<1000; i++){
if(i == 300 or i == 600 or i == 900){
std::cout << threadNum << " has reached step: " << i << std::endl;
}
}
}
int main()
{
std::cout << "Your Username Is: " << getenv("USER") << std::endl;
std::thread t1(task, "Thread 1");
std::thread t2(task, "Thread 2");
t1.join();
t2.join();
}
and I get different outputs every single time I run the program, for example
Your Username Is: gansaikhanshur
Thread 2 : Thread 1 : 0x70000741e000
Thread 2 has reached step: 0x70000739b000300
Thread 1 has reached step: 300
Thread 2 has reached step: 600
Thread 2 has reached step: 900
Thread 1 has reached step: 600
Thread 1 has reached step: 900
Thread1 and Thread 2 does not show it's thread ID as it should. Why do I get different results all the time? and Is it possible for me to make thread 1 and thread 2 to display their correct thread ids?
This is the way threads work -- they run independently and any side-effects they have may show up interleaved in any order. If you want to ensure that doesn't happen, you need to synchronize. For example, if you want to ensure that lines written to cout don't get mixed up, you can lock around each line output:
std::mutex cout_lock;
void task(std::string threadNum)
{
std::thread::id this_id = std::this_thread::get_id();
{
std::lock_guard<std::mutex> lock(cout_lock);
std::cout << threadNum << " : " << this_id << std::endl;
}
for(int i=0; i<1000; i++){
if(i == 300 or i == 600 or i == 900) {
std::lock_guard<std::mutex> lock(cout_lock);
std::cout << threadNum << " has reached step: " << i << std::endl;
}
}
}
lock_guard gives you a nice easy exception-safe way to manage lock/unlock operations.
Related
I have a sample code:
#include <iostream> // std::cout
#include <thread> // std::thread
void pause_thread(int n)
{
if(n != 4)
{
std::this_thread::sleep_for(std::chrono::seconds(100));
std::cout << "pause of " << 100 << " seconds ended\n";
}
std::cout << "Thread number " << n << " ended\n";
}
int main()
{
std::thread threads[6]; // default-constructed threads
std::setvbuf(stdout, NULL, _IONBF, 0);
std::cout << "Spawning 5 threads...\n";
for(int i = 0; i < 5; ++i)
{
//If the object is currently not joinable, it acquires the thread of execution represented by rhs (if any).
//If it is joinable, terminate() is called. If it is joinable, terminate() is called.
//rhs no longer represents any thread of execution
threads[i] = std::move(std::thread(pause_thread, i)); // move-assign threads
}
std::thread& i = threads[4];
threads[5] = std::move(threads[4]);
std::cout << "Done spawning threads. Now waiting for them to join:\n";
for(int i = 0; i < 6; ++i)
{
if(threads[i].joinable())
{
std::cout << "Thread " << i << " " << threads[i].get_id() << " ID joinable" << std::endl << std::flush;
threads[i].join();
}
else
{
std::cout << "Thread " << i << " not joinable" << std::endl << std::flush;
}
}
std::cout << "All threads joined!\n";
return 0;
}
Below is the output I received:
Spawning 5 threads...
Done spawning threads. Now waiting for them to join:
Thread 0 22476 ID joinable
Thread number 4 ended
.... no output for 100 seconds ..
pause of 100 seconds ended
Thread number 0 ended
pause of 100 seconds ended
Thread 1 28676 ID joinable
pause of 100 seconds ended
Thread number 2 ended
Thread number 3 ended
pause of 100 seconds ended
Thread number 1 ended
Thread 2 2336 ID joinable
Thread 3 42236 ID joinable
Thread 4 not joinable
Thread 5 35940 ID joinable
All threads joined!
How the "Thread n xxxx ID joinable" statements are getting printed after "Thread number n ended"? I have even tried using set std::output as non buffered but the output was same?
"Joinable" does not imply that the thread is still executing.
You first join thread #0. This will take ~100 seconds.
During that time, thread #4 finishes since it doesn't sleep, and the other threads are sleeping.
If the threads happen to be scheduled differently, any of the "sleep threads" could be printing that they've ended here.
Once the wait for thread #0 is over, you start joining the other threads.
Some of these have finished executing before you join them and some haven't.
In this particular instance, none of them finished before the wait for thread #0 was over, but there is no guarantee of that happening.
And note that a line like
std::cout << "Thread number " << n << " ended\n";
is not atomic and characters from different threads can be interleaved.
Because joinable does not mean what you think : https://en.cppreference.com/w/cpp/thread/thread/joinable
So any thread that is started is "joinable" it does not need to have finished running.
I'm trying to figure out how to use std::condition_variable in C++ implementing a "strange" producer and consumer program in which I had set a limit to the count variable.
The main thread ("producer") increments the count and must wait for this to return to zero to issue a new increment.
The other threads enters in a loop where they have to decrease the counter and issue the notification.
I am blocked because it is not clear to me how to conclude the program by orderly exiting the while loop inside the function of all threads.
Could someone give me some guidance on how to implement it, please?
Code
#include <iostream>
#include <thread>
#include <condition_variable>
#include <vector>
int main() {
int n_core = std::thread::hardware_concurrency();
std::vector<std::thread> workers;
int max = 100;
int count = 0;
std::condition_variable cv;
std::mutex mutex;
int timecalled = 0;
for (int i = 0; i < n_core; i++) {
workers.emplace_back(std::thread{[&max, &count, &mutex, &cv]() {
while (true) {
std::unique_lock<std::mutex> lk{mutex};
std::cout << std::this_thread::get_id() << " cv" << std::endl;
cv.wait(lk, [&count]() { return count == 1; });
std::cout << std::this_thread::get_id() << " - " << count << std::endl;
count--;
std::cout << std::this_thread::get_id() << " notify dec" << std::endl;
cv.notify_all();
}
}});
}
while (max > 0) {
std::unique_lock<std::mutex> lk{mutex};
std::cout << std::this_thread::get_id() << " cv" << std::endl;
cv.wait(lk, [&count]() { return count == 0; });
std::cout << std::this_thread::get_id() << " created token" << std::endl;
count++;
max--;
timecalled++;
std::cout << std::this_thread::get_id() << " notify inc" << std::endl;
cv.notify_all();
}
for (auto &w : workers) {
w.join();
}
std::cout << timecalled << std::endl; // must be equal to max
std::cout << count << std::endl; // must be zero
}
Problem
The program doesn't end because it is stuck on some final join.
Expected Result
The expected result must be:
100
0
Edits Made
EDIT 1 : I replaced max > 0 in the while with a true. Now the loops are unbounded, but using the solution of #prog-fh seems to work.
EDIT 2 : I added a variable to check the result in the end.
EDIT 3: I changed while(true) to while(max >0). Could this be a problem in concurrency because we are reading it without a lock?
The threads are waiting for something new in the call cv.wait().
But the only change that can be observed with the provided lambda-closure is the value of count.
The value of max must be checked too in order to have a chance to leave this cv.wait() call.
A minimal change in your code could be
cv.wait(lk, [&max, &count]() { return count == 1 || max<=0; });
if(max<=0) break;
assuming that changes to max always occur under the control of the mutex.
An edit to clarify around the accesses to max.
If the loop run by the threads is now while(true), then the max variable is only read in its body which is synchronised by mutex (thanks to lk).
The loop run by the main program is while (max > 0): max is read without synchronisation here but the only thread that can change this variable is the main program itself, so it's pure serial code from this perspective.
The whole body of this loop is synchronised by mutex (thanks to lk) so it is safe to change the value of max here since the read operations in the threads are synchronised in the same way.
You're having race conditions: in your code max may be read by multiple threads, whilst it is being modified in main, which is a race condition according to C++ standard.
The predicates you are using in wait seems to be incorrect (you're using ==).
I modified an asio strand example using the standalone version of the library from 4a here
#include <iostream>
#include <asio.hpp>
#include <future>
#include <thread>
#include <mutex>
#include <chrono>
using namespace std::chrono_literals;
namespace util
{
static std::mutex s_mtx_print;
// Default argument value
// https://en.cppreference.com/w/cpp/language/default_arguments
template <typename... Args>
void sync_print(const bool log_thread_id, Args &&... args)
{
std::lock_guard<std::mutex> print_lock(s_mtx_print);
if (log_thread_id)
{
std::cout << "[" << std::this_thread::get_id() << "] ";
}
(std::cout << ... << args) << '\n';
}
}
void Worker(std::unique_ptr<asio::io_service> &ios)
{
util::sync_print(true, " Started...");
if(ios) {ios->run();}
util::sync_print(true, " End");
}
void PrintNum(int n)
{
std::cout << "[" << std::this_thread::get_id() << "] " << n << '\n';
std::this_thread::sleep_for(300ms);
}
void OrderedInvocation(std::unique_ptr<asio::io_service::strand> &up_strand)
{
if(up_strand)
{
up_strand->post(std::bind(&PrintNum, 1));
up_strand->post(std::bind(&PrintNum, 2));
up_strand->post(std::bind(&PrintNum, 3));
up_strand->post(std::bind(&PrintNum, 4));
up_strand->post(std::bind(&PrintNum, 5));
up_strand->post(std::bind(&PrintNum, 6));
up_strand->post(std::bind(&PrintNum, 7));
up_strand->post(std::bind(&PrintNum, 8));
up_strand->post(std::bind(&PrintNum, 9));
}
else{
std::cerr << "Invalid strand" << '\n';
}
}
int main()
{
util::sync_print(true, "section 4 started ...");
auto up_ios = std::make_unique<asio::io_service>();
auto up_work = std::make_unique<asio::io_service::work>(*up_ios);
auto up_strand = std::make_unique<asio::io_service::strand>(*up_ios);
std::vector<std::future<void>> tasks;
constexpr int NUM_TASK = 3;
for(int i = 0; i< NUM_TASK; ++i)
{
tasks.push_back(std::async(std::launch::async, &Worker, std::ref(up_ios)));
}
std::cout << "Task size " << tasks.size() << '\n';
std::this_thread::sleep_for(500ms);
OrderedInvocation(up_strand);
up_work.reset();
for(auto &t: tasks){ t.get(); }
return 0;
}
The problem is: when I run the code, it appears that the function PrintNum only runs on a single thread
as the console output is
[140180645058368] section 4 started ...
Task size 3
[140180610144000] Started...
[140180626929408] Started...
[140180618536704] Started...
[140180610144000] 1
[140180610144000] 2
[140180610144000] 3
[140180610144000] 4
[140180610144000] 5
[140180610144000] 6
[140180610144000] 7
[140180610144000] 8
[140180610144000] 9
[140180610144000] End
[140180626929408] End
[140180618536704] End
My question is, do I need to configure the strand to let the tasks spread to all threads? Or maybe I missed something here?
[Edit]
Ideally, the output should be something like
[00154F88] The program will exit when all work has finished.
[001532B0] Thread Start
[00154FB0] Thread Start
[001532B0] x: 1
[00154FB0] x: 2
[001532B0] x: 3
[00154FB0] x: 4
[001532B0] x: 5
[00154FB0] Thread Finish
[001532B0] Thread Finish
Press any key to continue . . .
In the expected output, both thread 00154FB0 and 001532B0 executed the PrintNum(), but in the modified version, only one thread executed the PrintNum().
If the strand is not been used, the output is:
[140565152012096] section 4 started ...
[140565133883136] Started...
Task size 3
[140565117097728] Started...
[140565125490432] Started...
[[140565133883136] [140565117097728]] 12
3
[140565133883136] [4
[140565117097728140565125490432] 6
] 5
[140565133883136] 7
[140565125490432] 8
[140565117097728] 9
[140565125490432] End
[140565117097728] End
[140565133883136] End
Thanks
Here is the cpu info from the machine I am using
$lscpu
Thread(s) per core: 1
Core(s) per socket: 4
Socket(s): 1
The OS is Ubuntu 18.04
Rong
That's the purpose of a strand:
A strand is defined as a strictly sequential invocation of event handlers (i.e. no concurrent invocation). Use of strands allows execution of code in a multithreaded program without the need for explicit locking (e.g. using mutexes).
If you want parallel invocation, you will need to remove the strand, post() directly to io_service and invoke io_service::run from a number of threads (you're doing that already).
An unrelated note: there is no point in passing unique pointers around; make your life easier and just pass raw pointers or references.
This may be a bit late. However, I ran into the same issue, following the same example as above. It turns out the current way of using a strand is a bit different, as hinted here. Here is my revision on the original code:
#include <boost/asio/io_context.hpp>
#include <boost/asio/strand.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <memory>
#include <mutex>
#include <thread>
#include <chrono>
#include <vector>
#include <iostream>
namespace asio = boost::asio;
std::mutex global_stream_lock;
void
worker_thread(std::shared_ptr<asio::io_context> ioc) {
global_stream_lock.lock();
std::cout << "[" << std::this_thread::get_id() << "] Thread start"
<< std::endl;
global_stream_lock.unlock();
ioc->run();
global_stream_lock.lock();
std::cout << "[" << std::this_thread::get_id() << "] Thread finished"
<< std::endl;
global_stream_lock.unlock();
}
void
print_num(int x) {
std::cout << "[" << std::this_thread::get_id() << "] x = " << x
<< std::endl;
}
int
main() {
auto ioc = std::make_shared<asio::io_context>();
auto strand = asio::make_strand(*ioc);
auto work = asio::make_work_guard(*ioc);
global_stream_lock.lock();
std::cout << "[" << std::this_thread::get_id()
<< "] This thread will exit when all work is finished "
<< std::endl;
global_stream_lock.unlock();
std::vector<std::thread> thread_group;
for (int i = 0; i < 4; ++i) {
thread_group.emplace_back(std::bind(worker_thread, ioc));
}
for (int i = 0; i < 4; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
asio::post(strand, std::bind(print_num, 2 * i + 1));
asio::post(strand, std::bind(print_num, 2 * i + 2));
}
work.reset();
for (auto &t : thread_group) {
t.join();
}
}
This produces the following output:
[139877509977920] This thread will exit when all work is finished
[139877509973568] Thread start
[139877501580864] Thread start
[139877493188160] Thread start
[139877484795456] Thread start
[139877509973568] x = 1
[139877509973568] x = 2
[139877493188160] x = 3
[139877493188160] x = 4
[139877501580864] x = 5
[139877501580864] x = 6
[139877484795456] x = 7
[139877484795456] x = 8
[139877509973568] Thread finished
[139877493188160] Thread finished
[139877484795456] Thread finished
[139877501580864] Thread finished
I'm using boost 1.54.0 and Visual Studio 2010. For the code:
#include <iostream>
#include "boost/thread/thread.hpp"
#include "boost/thread/mutex.hpp"
boost::mutex mx1;
void func1()
{
{
boost::mutex::scoped_lock(mx1);
std::cout << "Thread " << boost::this_thread::get_id() << " starting work." << std::endl;
}
int x = 0;
for (int i=0; i<100; i++)
x++;
{
boost::mutex::scoped_lock(mx1);
std::cout << "Thread " << boost::this_thread::get_id() << " finished." << std::endl;
}
}
int main(void)
{
boost::thread thread1(&func1);
boost::thread thread2(&func1);
thread1.join();
thread2.join();
return 0;
}
About half the time I get the following (with varying thread ids and execution order, obviously):
Thread Thread 15b0 starting work.
1a18 starting work.
Thread 15b0 finished.
Thread 1a18 finished.
...instead of this (which is what I'd expect):
Thread 15b0 starting work.
Thread 1a18 starting work.
Thread 15b0 finished.
Thread 1a18 finished.
However, using
mx1.lock();
std::cout << "Thread " << boost::this_thread::get_id() << " starting work." << std::endl;
mx1.unlock();
...seems to work with no problems.
The output always seems to follow the same pattern. Am I using the mutex incorrectly, or is it something to do with std::cout?
Replace
boost::mutex::scoped_lock(mx1);
with
boost::mutex::scoped_lock lock(mx1);
you fell a victim of the most frequently occurring typo with the scoped lock:-)
I am new to multi thread programming, so this question might seem a little silly, but I really need to work this out so I can apply it to my project (which is way more complicated).
Follow is my code, I am trying to have 2 threads (parent and child) to update the same shared timer as they execute and stop when the timer reaches a specific limit.
But when I compile and execute this follow piece of code, there are 2 different outcomes: 1. child prints "done by child at 200000" but the program does not exit; 2. after child prints "done by child at 200000" and exits, parent keeps executing, prints a couple of dozen lines of "parent doing work" and "parent at 190000", then prints "done by parent at 200000" and the program exits properly.
The behavior I want is for whichever thread that updates the timer, hits the limit and exits, the other thread should stop executing and exit as well. I think I might be missing something trivial here, but I've tried changing the code in many ways and nothing I tried seem to work. Any help will be much appreciated :)
#include <iostream>
#include <unistd.h>
#include <mutex>
#include <time.h>
using namespace std;
mutex mtx;
int main () {
int rc;
volatile int done = 0;
clock_t start = clock();
volatile clock_t now;
rc = fork();
if (rc == 0) { //child
while (true) {
cout << "child doing work" << endl;
mtx.lock();
now = clock() - start;
if (done) {
mtx.unlock();
break;
}
if (now >= 200000 && !done) {
done = 1;
cout << "done by child at " << now << endl;
mtx.unlock();
break;
}
cout << "child at " << now << endl;
mtx.unlock();
}
_exit(0);
}
else { // parent
while (true) {
cout << "parent doing work" << endl;
mtx.lock();
now = clock() - start;
if (done) {
mtx.unlock();
break;
}
if (now >= 200000 && !done) {
done = 1;
cout << "done by parent at " << now << endl;
mtx.unlock();
break;
}
cout << "parent at " << now << endl;
mtx.unlock();
}
}
return 0;
}
Multi-processes
Your code is multi-processes and not multi-threading: fork() will create a new separate process by duplicating the calling process.
The consequence: At the moment of the duplication, all the variables contain the same value in both processes. But each process has its own copy, so a variable modified in the parent will not be updated in the child's address space an vice-versa.
If you want to share variables between processes, you should have a look at this SO question
Multithread
For real multithreading, you should use std::thread. And forget about volatile, because it's not thread safe. Use <atomic> instead, as explained in this awesome video.
Here a first try:
#include <iostream>
#include <mutex>
#include <thread>
#include <atomic>
#include <time.h>
using namespace std;
void child (atomic<int>& done, atomic<clock_t>& now, clock_t start)
{
while (!done) {
cout << "child doing work" << endl;
now = clock() - start;
if (now >= 2000 && !done) {
done = 1;
cout << "done by child at " << now << endl;
}
cout << "child at " << now << endl;
this_thread::yield();
}
}
void parent (atomic<int>& done, atomic<clock_t>& now, clock_t start)
{
while (!done) {
cout << "parent doing work" << endl;
now = clock() - start;
if (now >= 2000 && !done) {
done = 1;
cout << "done by parent at " << now << endl;
}
cout << "parent at " << now << endl;
this_thread::yield();
}
}
int main () {
atomic<int> done{0};
clock_t start = clock();
atomic<clock_t> now;
thread t(child, std::ref(done), std::ref(now), start); // attention, without ref, you get clones
parent (done, now, start);
t.join();
return 0;
}
Note that you don't need to protect atomic accesses with a mutex, and that if you want to do, lock_guard would be recommended alternative.
This example is of course rather weak, because if you test an atomic variable if the if-condition, it's value might already have changed when entering the if-block. This doesn't cause a problem in your logic where "done" means "done". But if you'd need a more cauthious approach,
compare_exchange_weak() or compare_exchange_strong() could help further.