I have multiple std::threads but only one of them should perform some task (say, printf) (similar to pragma omp single).
I've tried to modify semaphore code, but it doesn't work as I expected.
#ifndef SEMAPHORE_H
#define SEMAPHORE_H
#include <mutex>
#include <condition_variable>
using namespace std;
class semaphore {
private:
mutex mtx;
condition_variable cv;
int count, countMax;
public:
semaphore(int count_ = 0):count(count_), countMax(count_){;}
void notify()
{
unique_lock<mutex> lck(mtx);
++count;
cv.notify_one();
}
void notifyAll()
{
unique_lock<mutex> lck(mtx);
count = countMax;
cv.notify_all();
}
bool wait()
{
unique_lock<mutex> lck(mtx);
if (--count == 0) {
return true;
} else {
cv.wait(lck, [this]() { return count > 0; });
return false;
}
}
};
#endif // SEMAPHORE_H
And the main program:
#include <iostream>
#include <vector>
#include <thread>
#include "semaphore.h"
semaphore sem(2);
int sum = 0;
std::mutex sumMutex;
int sumPrintAndReturn(int i)
{
{
std::lock_guard<std::mutex> lock(sumMutex);
sum += i;
}
if (sem.wait()) {
std::cout << "Sum (ONCE): " << sum << std::endl;
sem.notifyAll();
}
std::cout << "Sum (EVERY): " << sum << std::endl;
return sum;
}
int main()
{
std::vector<std::thread> threads;
for (int i = 0; i < 2; i++) {
threads.push_back(std::thread(sumPrintAndReturn, i));
}
for (auto& thread: threads)
thread.join();
return 0;
}
The problem is that final sum is different.
Sum (EVERY): 0
Sum (ONCE): 1
Sum (EVERY): 1
So why I'm talking about omp single? Here is an example and output I expect.
#include <iostream>
#include <omp.h>
int main()
{
int sum = 0;
int global_i = 0;
#pragma omp parallel num_threads(2)
{
int i;
#pragma omp critical
i = global_i++;
#pragma omp atomic
sum += i;
#pragma omp single
printf("Sum (ONCE): %d\n", sum);
printf("Sum (EVERY): %d\n", sum);
}
}
And output:
Sum (ONCE): 1
Sum (EVERY): 1
Sum (EVERY): 1
I can't answer my thread so I'll post final and working variant here
#ifndef SEMAPHORE_H
#define SEMAPHORE_H
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <functional>
class semaphore {
private:
std::mutex mtx;
std::condition_variable cv;
std::atomic<int> count;
const int countMax;
bool flag;
void releaseAll()
{
std::unique_lock<std::mutex> lck(mtx);
flag = true;
cv.notify_all();
cv.wait(lck, [this]() { return !flag; });
}
bool wait()
{
std::unique_lock<std::mutex> lck(mtx);
if (--count == 0) {
count++;
return false;
}
else {
cv.wait(lck, [this]() { return flag; });
count++;
if (count == countMax) {
flag = false;
cv.notify_all();
}
cv.wait(lck, [this]() { return !flag; });
return true;
}
}
public:
semaphore(int count_ = 0) :count(count_), countMax(count_), flag(false){ }
void runOnce(std::function<void()> func) {
if (!wait()) {
func();
releaseAll();
}
}
};
#endif // SEMAPHORE_H