C# 改进多线程代码设计以防止争用情况
我遇到了一个问题,我不确定是否可以用我想要的方式解决它。我对比赛条件有问题C# 改进多线程代码设计以防止争用情况,c#,c++,multithreading,winapi,race-condition,C#,C++,Multithreading,Winapi,Race Condition,我遇到了一个问题,我不确定是否可以用我想要的方式解决它。我对比赛条件有问题 我有一个项目作为C++ DLL(主引擎)运行。 然后我有第二个C#进程,它使用C++/CLI与主引擎(编辑器)通信 编辑器将引擎窗口作为子窗口托管。其结果是子窗口异步接收输入消息(请参见RiProcessMouseMessage())。通常只有在调用window->PollEvents()时才会发生这种情况 因此,您可以看到,当在主引擎循环中调用RiProcessMouseMessage()而调用Reset()时,竞争条
我有一个项目作为C++ DLL(主引擎)运行。 然后我有第二个C#进程,它使用C++/CLI与主引擎(编辑器)通信
编辑器将引擎窗口作为子窗口托管。其结果是子窗口异步接收输入消息(请参见RiProcessMouseMessage()
)。通常只有在调用window->PollEvents()时才会发生这种情况代码>
因此,您可以看到,当在主引擎循环中调用RiProcessMouseMessage()
而调用Reset()
时,竞争条件发生。如果不清楚:需要使用Reset()
函数将状态重置回其帧的默认数据,以便每帧都能正确读取数据
现在我非常清楚,我可以通过在gatherState更新周围添加一个mutex
来轻松解决这个问题,但如果可能的话,我希望避免这种情况。基本上,我是在问,有没有可能重新设计此代码,使其无锁?您是在问无锁,如果两端都改变了缓冲区,这是不太可能的。但若你们要求锁是优化的,几乎是瞬时的,那个么你们可以使用FIFO逻辑。您可以使用.net的ConcurrentQueue“https://docs.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentqueue-1?view=net-5.0“从该队列写入更新和轮询更新
如果你真的摆脱了锁,那么你可以检查无锁循环数组,也称为无锁环缓冲,
如果您想深入了解硬件级别以了解其背后的逻辑,那么您可以进行检查,以便了解底层的并发性;受限制,当一端仅在已知间隔/边界内写入,而另一端仅在已知间隔/边界内读取时,无锁环形缓冲区可以工作。可以检查所问的类似问题:
Boost有著名的无锁实现:Hmm,,是的,队列实际上可以在这里工作。我实际上需要它在C++中,但是我已经有一个并发队列实现。我明天就试一试。谢谢你的建议,有时候我只是需要一双眼睛来看待问题。
main engine loop {
RiProcessMouseMessage(); // <- Called by the default windows message poll function from the child window
foreach(inputDevice)
inputDevice->UpdateState();
otherCode->UseCurrentInput();
}
main editor loop {
RiProcessMouseMessage(); // <- This one is called by the editor (parent) window, but is using the message loop of the (child) engine window
}
void Win32RawInput::RiProcessMouseMessage(const RAWMOUSE& rmouse, HWND hWnd) {
MouseState& state = Input::mouse._GetGatherState();
// Check Mouse Position Relative Motion
if (rmouse.usFlags == MOUSE_MOVE_RELATIVE) {
vec2f delta((float)rmouse.lLastX, (float)rmouse.lLastY);
delta *= MOUSE_SCALE;
state.movement += delta;
POINT p;
GetCursorPos(&p);
state.cursorPosGlobal = vec2i(p.x, p.y);
ScreenToClient(hWnd, &p);
state.cursorPos = vec2i(p.x, p.y);
}
// Check Mouse Wheel Relative Motion
if (rmouse.usButtonFlags & RI_MOUSE_WHEEL)
state.scrollMovement.y += ((float)(short)rmouse.usButtonData) / WHEEL_DELTA;
if (rmouse.usButtonFlags & RI_MOUSE_HWHEEL)
state.scrollMovement.x += ((float)(short)rmouse.usButtonData) / WHEEL_DELTA;
// Store Mouse Button States
for (int i = 0; i < 5; i++) {
if (rmouse.usButtonFlags & maskDown_[i]) {
state.mouseButtonState[i].pressed = true;
state.mouseButtonState[i].changedThisFrame = true;
} else if (rmouse.usButtonFlags & maskUp_[i]) {
state.mouseButtonState[i].pressed = false;
state.mouseButtonState[i].changedThisFrame = true;
}
}
}
void UpdateState() {
currentState = gatherState; // Copy gather state to current
Reset(gatherState); // Reset the old buffer so the next time the buffer it's used it's all good
// Use current state to check stuff
// For the rest of this frame currentState should be used
}
MouseState& _GetGatherState() { return gatherState; }
void Reset(MouseState& state) { // Might need a lock around gatherState :(
state.movement = vec2f::zero;
state.scrollMovement = vec2f::zero;
for (int i = 0; i < 5; ++i)
state.mouseButtonState[i].changedThisFrame = false;
}