What happens if two threads read & write the same piece of memory

这一生的挚爱 提交于 2019-11-29 02:23:35

The result is undefined. Corrupted data is entirely possible. For an obvious example, consider a 64-bit value being manipulated by a 32-bit processor. Let's assume the value is a simple counter, and we increment it when the lower 32-bits contain 0xffffffff. The increment produces 0x00000000. When we detect that, we increment the upper word. If, however, some other thread read the value between the time the lower word was incremented and the upper word was incremented, they get a value with an un-incremented upper word, but the lower word set to 0 -- a value completely different from what it would have been either before or after the increment is complete.

Usually memory is read or written in atomic units determined by the CPU architecture (32 bit and 64 bits item aligned on 32 bit and 64 bit boundaries is common these days).

In this case, what happens depends on the amount of data being written.

Let's consider the case of 32 bit atomic read/write cells.

If two threads write 32 bits into such an aligned cell, then it is absolutely well defined what happens: one of the two written values is retained. Unfortunately for you (well, the program), you don't know which value. By extremely clever programming, you can actually use this atomicity of reads and writes to build synchronization algorithms (e.g., Dekker's algorithm), but it is faster typically to use architecturally defined locks instead.

If two threads write more than an atomic unit (e.g., they both write a 128 bit value), then in fact the atomic unit sized pieces of the values written will be stored in a absolutely well defined way, but you won't know which pieces of which value get written in what order. So what may end up in storage is the value from the first thread, the second thread, or mixes of the bits in atomic unit sizes from both threads.

Similar ideas hold for one thread reading, and one thread writing in atomic units, and larger.

Basically, you don't want to do unsynchronized reads and writes to memory locations, because you won't know the outcome, even though it may be very well defined by the architecture.

snemarch

As I hinted in Ira Baxter's answer, CPU cache also plays a part on multicore systems. Consider the following test code:

DANGER WILL ROBISON!

The following code boosts priority to realtime to achieve somewhat more consistent results - while doing so requires admin privileges, be careful if running the code on dual- or single-core systems, since your machine will lock up for the duration of the test run.

#include <windows.h>
#include <stdio.h>

const int RUNFOR = 5000;
volatile bool terminating = false;
volatile int value;

static DWORD WINAPI CountErrors(LPVOID parm)
{
    int errors = 0;
    while(!terminating)
    {
        value = (int) parm;
        if(value != (int) parm)
            errors++;
    }
    printf("\tThread %08X: %d errors\n", parm, errors);
    return 0;
}

static void RunTest(int affinity1, int affinity2)
{
    terminating = false;
    DWORD dummy;
    HANDLE t1 = CreateThread(0, 0, CountErrors, (void*)0x1000, CREATE_SUSPENDED, &dummy);
    HANDLE t2 = CreateThread(0, 0, CountErrors, (void*)0x2000, CREATE_SUSPENDED, &dummy);

    SetThreadAffinityMask(t1, affinity1);
    SetThreadAffinityMask(t2, affinity2);
    ResumeThread(t1);
    ResumeThread(t2);

    printf("Running test for %d milliseconds with affinity %d and %d\n", RUNFOR, affinity1, affinity2);
    Sleep(RUNFOR);
    terminating = true;
    Sleep(100); // let threads have a chance of picking up the "terminating" flag.
}

int main()
{
    SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
    RunTest(1, 2);      // core 1 & 2
    RunTest(1, 4);      // core 1 & 3
    RunTest(4, 8);      // core 3 & 4
    RunTest(1, 8);      // core 1 & 4
}

On my Quad-core intel Q6600 system (which iirc has two sets of cores where each set share L2 cache - would explain the results anyway ;)), I get the following results:

Running test for 5000 milliseconds with affinity 1 and 2
        Thread 00002000: 351883 errors
        Thread 00001000: 343523 errors
Running test for 5000 milliseconds with affinity 1 and 4
        Thread 00001000: 48073 errors
        Thread 00002000: 59813 errors
Running test for 5000 milliseconds with affinity 4 and 8
        Thread 00002000: 337199 errors
        Thread 00001000: 335467 errors
Running test for 5000 milliseconds with affinity 1 and 8
        Thread 00001000: 55736 errors
        Thread 00002000: 72441 errors
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!