'Is synchronization required when passing a cancel flag with P/Invoke?
I am passing a cancel flag by reference (or by pointer) to a C++ DLL by P/Invoke. The flag will be set at some time in C# code, and the C++ code checks for the flag and returns when the flag is set. Is there a need to do synchronization somewhere?
As the C++ code reads the flag while the C# code is writing the flag, a data race is present. "Effective Modern C++" recommends using std::atomic for concurrency to avoid data race problems but it's not available in P/Invoke situation. I think the flag should be defined as volatile to avoid the C++ compiler to optimize away the read from cancel flag, but I was told that volatile shouldn't be used in concurrency situations.
The C++ function is like this:
void doSomething(int &cancelFlag) {
while (true) {
...
if (cancelFlag != 0) {
return;
}
}
}
Update: the C# code is like the following. And I found that the "canCancel" is another data race.
// token is a CancellationToken
IntPtr cancelFlag = Marshal.AllocHGlobal(Marshal.SizeOf<int>());
Marshal.WriteInt32(cancelFlag, 0);
bool canCancel = true;
token.Register(() =>
{
if (canCancel)
{
Marshal.WriteInt32(cancelFlag, 1);
}
});
doSomething(cancelFlag);
canCancel = false;
Marshal.FreeHGlobal(cancelFlag);
Solution 1:[1]
I achieved this by using a syncrhonized variable on one side and use a function to access that from the other side.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Zhaoquan Huang |