Consider following code:
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
#include <chrono>
using namespace std;
const int SIZE = 10;
mutex myMutex;
std::vector<int> strange;
void add_to_vector(int i) {
lock_guard<mutex> g(myMutex);
if (strange.size() < 100) {
cout << "Dodaje do bazy" << i << std::endl;
strange.push_back(i);
cout << "Dodałem do bazy" << i << std::endl;
}
}
void f(int n) {
while (strange.size() < 100)
{
add_to_vector(n);
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
}
int main()
{
thread t1(f, 1); // 0-9
thread t2(f, 2); // 10-19
thread t3(f, 3); // 20-29
thread t4(f, 4); // 30-39
thread t5(f, 5); // 40-49
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
for (auto a : strange) {
std::cout << a << ", ";
}
return 0;
}
Is threads waiting to mutex unlock, lining up ? It seems that after unlocking , access to resources gets a random thread. How to ensure that they get access to the resource threads in FIFO order ?
Related
in below code snippet it looks like notification from producer thread to consumer thread is not reaching once producer produce an single item and due to this behavior once producer has finished generating items equivalent to buffer size then only consumer has started consuming items . Can anybody suggest How we should approach to fix this issue using semaphore.
#include <iostream>
#include <queue>
#include <semaphore.h>
#include <thread>
#include <functional>
const int BUFFER_SIZE = 3;
class Buffer {
public:
sem_t sem_full;
sem_t sem_empty;
std::queue<int> buffer;
Buffer() {
sem_init(&sem_full, 0, BUFFER_SIZE);
sem_init(&sem_empty, 0, 0);
}
void producer() {
while (true) {
sem_wait(&sem_full);
int item = rand() % 10;
buffer.push(item);
std::cout << "Producer added " << item << std::endl;
sem_post(&sem_empty);
if (buffer.size() == BUFFER_SIZE) {
std::cout << "Buffer is full, terminating producer thread" << std::endl;
return;
}
}
}
void consumer() {
while (true) {
sem_wait(&sem_empty);
int item = buffer.front();
buffer.pop();
std::cout << "Consumer removed " << item << std::endl;
sem_post(&sem_full);
if (buffer.empty()) {
std::cout << "Buffer is empty, terminating consumer thread" << std::endl;
return;
}
}
}
};
int main() {
Buffer buffer;
std::thread producer(std::bind(&Buffer::producer, &buffer));
std::thread consumer(std::bind(&Buffer::consumer, &buffer));
producer.join();
consumer.join();
return 0;
}
you need to use binary semaphore here to achieve this behavior without using condition variable to synchronize this.
#include <iostream>
#include <queue>
#include <semaphore.h>
#include <thread>
#include <functional>
#include <condition_variable>
#include <mutex>
#include <atomic>
const int BUFFER_SIZE = 4;
class Buffer {
public:
sem_t sem_full;
sem_t sem_empty;
std::queue<int> buffer;
std::condition_variable cv;
std::mutex m;
int buffer_full_count {0};
Buffer() {
sem_init(&sem_full, 0, 1);
sem_init(&sem_empty, 0, 0);
}
void producer() {
while (true) {
sem_wait(&sem_full);
if (buffer_full_count == BUFFER_SIZE) {
std::cout << "Buffer is full, terminating producer thread" << std::endl;
return;
}
std::unique_lock <std::mutex> lock(m);
int item = rand() % 10;
buffer.push(item);
buffer_full_count++;
std::cout << "Producer added " << item << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
sem_post(&sem_empty);
}
}
void consumer() {
while (buffer_full_count != BUFFER_SIZE) {
sem_wait(&sem_empty);
std::unique_lock <std::mutex> lock(m);
int item = buffer.front();
buffer.pop();
std::cout << "Consumer removed " << item << std::endl;
sem_post(&sem_full);
}
}
};
int main() {
Buffer buffer;
std::thread producer(std::bind(&Buffer::producer, &buffer));
std::thread consumer(std::bind(&Buffer::consumer, &buffer));
producer.join();
consumer.join();
return 0;
}
In my program I need to start 2 pieces of external hardware.
This is somewhat time consuming and I therefore want to run it in separate threads.
The start-up has two parts. The second part, hardwareTask2(), must be performed ca. simultaneously on both threads.
I therefore want to use a std::barrier to synchronize before calling this method.
However, the first part of the start-up, hardwareTask1() may fail.
If it fails on either thread I want both threads to return.
How do I achieve this?
Using std::barrier::arrive_and_drop() below I have managed to at least get the other thread to finish (not wait indefinitely at the barrier).
#include <iostream>
#include <thread>
#include <barrier>
bool hardwareTask1(unsigned int id) {
srand(id);
int r = rand() % 10;
std::this_thread::sleep_for(std::chrono::seconds(r));
return true;
}
// must be called ca. simultaneously:
void hardwareTask2() {
std::this_thread::sleep_for(std::chrono::seconds(5));
}
void startHardware(unsigned int id, std::barrier<>& b) {
bool ok = hardwareTask1(id);
// Simulate that the above function failed for the first thread:
if (id == 1) {
ok = false;
}
if (!ok) {
b.arrive_and_drop();
return;
}
std::cerr << id << ": finished task1\n";
b.arrive_and_wait();
std::cerr << id << ": after barrier\n";
hardwareTask2();
}
int main()
{
std::barrier<> b(2);
std::thread t1(&startHardware, 1, std::ref(b));
std::thread t2(&startHardware, 2, std::ref(b));
t1.join();
t2.join();
std::cerr << "Both threads have finished.\n";
int k;
std::cin >> k;
}
Like #UlrichEckhardt mentioned in his comment, you can use a std::future, std::promise pair to do the synchronization. Small example:
#include <iostream>
#include <future>
#include <random>
#include <thread>
void hardwareTask1(std::promise<bool> p)
{
std::cout << "HW 1: First part\n";
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> distrib(1, 10);
std::this_thread::sleep_for(std::chrono::seconds(distrib(gen)));
int res = distrib(gen);
if (res > 5) {
p.set_value(true);
std::cout << "HW 1: Second part\n";
}
else {
p.set_value(false);
std::cout << "HW 1: First part failed - abort\n";
}
}
void hardwareTask2(std::future<bool> f)
{
std::cout << "HW 2: First part\n";
if (f.get())
std::cout << "HW 2: Second part\n";
else
std::cout << "HW 2: HW 1 failed - abort\n";
}
int main()
{
std::promise<bool> p;
std::thread t2(&hardwareTask2, p.get_future());
std::thread t1(&hardwareTask1, std::move(p));
t1.join();
t2.join();
}
Thanks in advance for any help.
Trying to make a program that would create 6 threads, then each 2 seconds randomly choose one and make it print its number. I am obviously doing something wrong, because it just keeps printing 0-1-2-3-4-5 endlessly. The code is below.
Main question is, what should i do to make random threads unlock?
#include <thread>
#include <memory>
#include <chrono>
#include <condition_variable>
std::condition_variable* cv = new std::condition_variable();
std::mutex cv_m;
void threadFunc(std::shared_ptr<bool> flag2, int id)
{
while (true)
{
std::unique_lock<std::mutex> lock(cv_m);
cv->wait(lock);
if (true)
if (*flag2) std::cout << "Thread" << " " << id << std::endl;
}
}
int main() {
std::shared_ptr<bool> f2 = std::make_shared<bool>(false);
std::thread threads[6];
for (int i = 0; i < 6; i++)
threads[i] = std::thread(threadFunc, f2, i);
*f2 = true;
while (true)
{
cv->notify_one();
std::this_thread::sleep_for(std::chrono::seconds(2));
}
return 0;
}
You can use a condition variable for each thread, it should be false for each thread at the beginning, then change a random condition variable to true and notify all, this will make a random thread to wake up (the thread that owns that condition variable)
here is the full solution
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <unistd.h>
#include "UserInterruptHandler.h"
using namespace std;
UserInterruptHandler h;
condition_variable conditionalVariable;
mutex mtx;
bool flag = true;
void myMethod(int id, bool *canWork) {
unique_lock<mutex> ul(mtx);
while (flag) {
conditionalVariable.wait(ul,[=]{return *canWork;});
if(!flag)
break;
cout << "thread " << id << endl;
}
cout << "thread " << id << " exits.." << endl;
}
int main() {
cout << "input thread count" << endl;
int n;
cin >> n;
thread myThreads[n];
bool *canWork = new bool[n];
for (int i = 0; i < n; i++) {
canWork[i] = false;
myThreads[i] = thread(myMethod, i + 1, &canWork[i]);
}
while (!h.checkInterruption()) {
int i = rand() % n;
canWork[i] = true;
conditionalVariable.notify_all();
canWork[i] = false;
usleep(1000);
}
flag = false;
int i = 0;
for (thread &th:myThreads) {
canWork[i++] = true;
conditionalVariable.notify_all();
if (th.joinable())
th.join();
}
}
notice that here I am using header UserInterruptHandler.h to handle CTR+C event to end all threads gracefully
This question is a follow up for this question. I want threads to perform some work and pass handle to the next thread in order. When trying to execute the following code, I get
Unhandled exception at 0x0F7C1F5F (msvcp120d.dll) in ConsoleApplication9.exe: 0xC0000005 : Access violation reading location 0x00000004.
#include "stdafx.h"
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
#include <condition_variable>
std::mutex* m_pMutexs;
std::condition_variable* m_pCVs;
int m_pCurrentWorker;
void func(int i)
{
int cvCurrentInd = i;
std::mutex* pCurMutex = &m_pMutexs[cvCurrentInd];
std::condition_variable* pCuCV = (std::condition_variable*)(m_pCurrentWorker + i*sizeof(std::condition_variable));
std::unique_lock<std::mutex> lk(m_pMutexs[i]);
while (i != m_pCurrentWorker)
{
pCuCV->wait(lk);
}
std::cout << "entered thread " << std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(rand() % 10));
std::cout << "leaving thread " << std::this_thread::get_id() << std::endl;
m_pCurrentWorker++;
lk.unlock();
pCuCV->notify_one();
}
int _tmain(int argc, _TCHAR* argv[])
{
m_pMutexs = new std::mutex[3];
m_pCVs = new std::condition_variable[3];
m_pCurrentWorker = 0;
srand((unsigned int)time(0));
std::thread t1(func,0);
std::thread t2(func,1);
std::thread t3(func,2);
t1.join();
t2.join();
t3.join();
return 0;
}
Have no idea what you're trying to do but
You're casting integer to pointer?
std::condition_variable* pCuCV = (std::condition_variable*)(m_pCurrentWorker + i*sizeof(std::condition_variable));
I think you should write instead:
std::condition_variable* pCuCV = &m_pCVs[i];
The whole function could be something like this:
void func(int i)
{
std::mutex* pCurMutex = &m_pMutexs[i];
std::condition_variable* pCuCV = &m_pCVs[i];
std::unique_lock<std::mutex> lk(m_pMutexs[i]);
while (i != m_pCurrentWorker) {
pCuCV->wait(lk);
}
std::cout << "entered thread " << std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(rand() % 2));
std::cout << "leaving thread " << std::this_thread::get_id() << std::endl;
m_pCurrentWorker++;
lk.unlock();
if (m_pCurrentWorker > 2) {
return;
}
pCuCV = &m_pCVs[m_pCurrentWorker];
pCuCV->notify_one();
}
I did some further research and it seems that the code the original questions is not thread-safe
I'm trying to learn the condition variables, and I'm stuck at the following example. I thought that notify_one on consumers should unlock only one waiting consumer. But after starting it repeatedly it seems to me that this isn't the case. I've changed notify_one into notify_all and haven't noticed a change in behavior. After the producer calls notify_one on consumers I can see Get… being written on screen by more then one consumer.
Why is this happening?
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
#include <chrono>
std::mutex mtx;
std::condition_variable produce,consume;
int cargo = 0; // shared value by producers and consumers
void consumer () {
std::unique_lock<std::mutex> lck(mtx);
while (cargo==0) consume.wait(lck);
std::cout << "Get" << cargo << " "<< std::this_thread::get_id() << '\n';
cargo--;
produce.notify_one();
}
void producer (int id) {
std::unique_lock<std::mutex> lck(mtx);
while (cargo!=0) produce.wait(lck);
std::cout << "Push" << id << " "<< std::this_thread::get_id() << '\n';
cargo += id;
consume.notify_one();
}
void c () {
while(1) {
consumer();
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
void p(int n) {
while(1) {
producer(n);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
int main ()
{
std::thread consumers[5],producers[5];
for (int i=0; i<5; ++i) {
consumers[i] = std::thread(c);
producers[i] = std::thread(p,i+1);
}
for (int i=0; i<5; ++i) {
producers[i].join();
consumers[i].join();
}
return 0;
}