Exchanger
应该提供一种交换方法,让两个线程立即交换它们的对象。即使没有死锁,某些线程也会得到错误的结果。通过调试,我发现两个指针之一的值被随机地改变了一个,我不明白为什么。
#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;
}
此外,int exchange
是否应该在函数末尾销毁t<int>
参数?为什么int* p
仍然指向实际上是副本的传递值?
答案 0 :(得分:0)
通过调试,我看到两个指针之一获得了它的值 改变了一些随机的,我不明白为什么
p1
和p2
将地址存储到函数的局部变量:
T exchange(T t) {
std::unique_lock lock(mutex);
if (!ready) {
p1 = &t; // <------HERE - STORING ADDRESS TO LOCAL VARIABLE
ready = true;
to_exchange.wait(lock, [this]{return !ready;});
return *p2;
} else {
p2 = &t; // <------HERE - STORING ADDRESS TO LOCAL VARIABLE
ready = false;
to_exchange.notify_one();
return *p1;
}
}
函数结束时,此局部变量超出范围,导致p1
和p2
成为悬空指针。访问悬空指针是未定义的行为,这也解释了调试时获得的随机值。
而不是存储变量的地址store a copy。