Exchanger
should provide an exchange method to let two threads at once to exchange their objects. Even tho there's no deadlock some threads got a wrong result. Debugging through I see that one of the two pointers got its value changed with some random one and I'm not able to understand why.
#include <mutex>
#include <condition_variable>
#include <thread>
#include <iostream>
#include <sstream>
#include <vector>
#include <random>
#include <queue>
template <typename T>
class Exchanger {
inline static Exchanger* instance;
inline static std::once_flag inited;
std::mutex mutex;
std::condition_variable to_exchange;
T* p1 = nullptr;
T* p2 = nullptr;
bool ready = false;
Exchanger(){};
~Exchanger(){};
public:
static Exchanger* getInstance() {
std::call_once(inited, []{
instance = new Exchanger();
});
return instance;
}
T exchange(T t) {
std::unique_lock lock(mutex);
if (!ready) {
p1 = &t;
ready = true;
to_exchange.wait(lock, [this]{return !ready;});
return *p2;
} else {
p2 = &t;
ready = false;
to_exchange.notify_one();
return *p1;
}
}
};
int* p = nullptr;
int exchange(int t) {
p = &t;
}
int main(int argc, char **argv) {
int x = 10;
exchange(x);
std::cout << *p << std::endl;
std::vector<std::thread> traders;
for (int i = 0; i < 4; i++) {
traders.emplace_back([i]{
std::this_thread::sleep_for(std::chrono::seconds(rand() % 2));
std::stringstream msg1;
msg1 << "thread " << std::this_thread::get_id() << " willing to trade " << i << std::endl;
std::cout << msg1.str();
std::stringstream msg2;
msg2 << "thread " << std::this_thread::get_id() << " got " << Exchanger<int>::getInstance()->exchange(i) << std::endl;
std::cout << msg2.str();
});
}
for (int i = 4; i < 8; i++) {
traders.emplace_back([i]{
std::this_thread::sleep_for(std::chrono::seconds(rand() % 2));
std::stringstream msg1;
msg1 << "thread " << std::this_thread::get_id() << " willing to trade " << i << std::endl;
std::cout << msg1.str();
std::stringstream msg2;
msg2 << "thread " << std::this_thread::get_id() << " got " << Exchanger<int>::getInstance()->exchange(i) << std::endl;
std::cout << msg2.str();
});
}
for (auto &t: traders) {
if (t.joinable()) {
t.join();
}
}
return 0;
}
Also, shouldn't int exchange
destroy the t<int>
parameter at the end of the function? Why is the int* p
still pointing to the passed value that is in fact a copy?