2

我正在阅读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;
}

编辑:

好的,尽管在这种特殊情况下它不会破坏单链表而不会保护Next()操作,但通常应该对共享结构进行整体保护或不保护。

4

3 回答 3

5

return node->next performs two operations; it first loads the struct pointed to by node into memory, then looks at the node+offsetof(next) to find the pointer next, load that into a register, and then return to the calling program. The contents of node may be manipulated by another thread of execution in the meantime.

于 2012-06-29T00:42:46.317 回答
1
  1. Yes, you absolutely need to protect your "next" with a lock in a multithreaded application.

... HOWEVER ...

  1. "Writers" (like add or remove node) MUST be mutually exclusive. Critical section is a good choice.

  2. "Readers" (like "next") can run concurrently with each other.

SUGGESTION:

If you can target Windows Vista or higher, consider using an SRW lock instead:

于 2012-06-29T00:51:50.343 回答
1

While I think the answer by sarnold is correct, I just wanted to point out that the sizeof() call in your malloc() call in CreateList appears to have a bug. I believe it should be:

List *pList = malloc(sizeof(List));

The way you had it, you will create enough memory to hold a pointer to a List and not the List structure. (You may also want to cast the return type to (List*) and compare it to NULL before using it..)

于 2012-06-29T00:53:28.223 回答