为什么单个链表的Next()操作应该用关键部分保护?

Eri*_*c Z 2 c++ winapi multithreading

我正在阅读Win32中的多线程应用程序一书

该书说return node->next将被编译成单独的机器指令,这些指令不会作为原子操作执行,因此Next()也应该受到关键部分的保护.

我的问题是,它可以转化为什么指令,导致竞争条件?

typedef struct _Node
{
    struct Node *next;
    int data;
} Node;

typedef struct _List
{
    Node *head;
    CRITICAL SECTION critical_sec;
} List;

List *CreateList()
{
    List *pList = malloc(sizeof(List));
    pList->head = NULL;
    InitializeCriticalSection(&pList->critical_sec);
    return pList;
}

void DeleteList(List *pList)
{
    DeleteCriticalSection(&pList->critical_sec);
    free(pList);
}

void AddHead(List *pList, Node *node)
{
    EnterCriticalSection(&pList->critical_sec);
    node->next = pList->head;
    pList->head = node;
    LeaveCriticalSection(&pList->critical_sec);
}

void Insert(List *pList, Node *afterNode, Node *newNode)
{
    EnterCriticalSection(&pList->critical_sec);
    if (afterNode == NULL)
    {
        AddHead(pList, newNode);
    }
    else
    {
        newNode->next = afterNode->next;
        afterNode->next = newNode;
    }
    LeaveCriticalSection(&pList->critical_sec);
}

Node *Next(List *pList, Node *node)
{
    Node* next;
    EnterCriticalSection(&pList->critical_sec);
    next = node->next;
    LeaveCriticalSection(&pList->critical_sec);
    return next;
}
Run Code Online (Sandbox Code Playgroud)

编辑:

好的,虽然在这种特殊情况下它不会破坏单链表而不保护Next()操作,但是共享结构通常应该作为一个整体或全部保护.

sar*_*old 5

return node->next执行两个操作; 它首先将struct指向的内容加载node到内存中,然后查看node+offsetof(next)指针next,将其加载到寄存器中,然后返回到调用程序.node在此期间,内容可以由另一个执行线程操纵.