'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