Bor*_*rov 7 c++ x86 multithreading race-condition undefined-behavior
我有一个应用程序对象,它可以从运行在多个线程中的多个服务接收消息。该消息由服务线程中的调度程序对象的实例在内部进行调度。该应用程序可以随时更改当前调度程序。调度员永远不会被摧毁。服务永远不会超过应用程序。
这是一个示例代码
#include <iostream>
#include <thread>
#include <atomic>
#include <cstdlib>
#include <functional>
using namespace std;
using Msg = int;
struct Dispatcher
{
virtual ~Dispatcher() = default;
virtual void dispatchMessage(Msg msg) = 0;
};
struct DispatcherA : Dispatcher
{
void dispatchMessage(Msg msg)
{
cout << "Thread-safe dispatch of " << msg << " by A" << endl;
}
};
struct DispatcherB : Dispatcher
{
void dispatchMessage(Msg msg)
{
cout << "Thread-safe dispatch of " << msg << " by B" << endl;
}
};
struct Application
{
Application() : curDispatcher(&a) {}
void sendMessage(Msg msg)
{
// race here as this is called (and dereferenced) from many threads
// and can be changed by the main thread
curDispatcher->dispatchMessage(msg);
}
void changeDispatcher()
{
// race her as this is changed but can be dereferenced by many threads
if (rand() % 2) curDispatcher = &a;
else curDispatcher = &b;
}
atomic_bool running = true;
Dispatcher* curDispatcher; // race on this
DispatcherA a;
DispatcherB b;
};
void service(Application& app, int i) {
while (app.running) app.sendMessage(i++);
}
int main()
{
Application app;
std::thread t1(std::bind(service, std::ref(app), 1));
std::thread t2(std::bind(service, std::ref(app), 20));
for (int i = 0; i < 10000; ++i)
{
app.changeDispatcher();
}
app.running = false;
t1.join();
t2.join();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我知道这里有比赛条件。该curDispatcher指针被多个线程访问,它可以在同一时间由主线程来改变。可以通过使指针原子化并在每次sendMessage调用时显式加载它来修复该问题。
我不想付出原子负载的代价。
会发生不好的事情吗?
这是我能想到的:
curDispatcher可以由服务缓存,即使应用程序更改了值,它也可以始终调用相同的值。我可以。如果我不再对此表示满意,则可以使其变得不稳定。无论如何,新创建的服务应该可以。| 归档时间: |
|
| 查看次数: |
117 次 |
| 最近记录: |