为什么单向链表的 Next() 操作应该用关键部分来保护
Why should Next() operation of a singly linked list be protected with a critical section?
>我正在阅读《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()
操作的单向链表,但通常应该保护整个共享结构或什么都不保护。
return node->next
执行两个操作;它首先将node
指向的struct
加载到内存中,然后查看node+offsetof(next)
以查找指针next
,将其加载到寄存器中,然后返回到调用程序。在此期间,node
的内容可能会被另一个执行线程操作。
- 是的,您绝对需要在多线程应用程序中使用锁定来保护您的"下一个"。
。然而。。。
-
"编写器"(如添加或删除节点)必须是互斥的。 关键部分是一个不错的选择。
" 读取器"(如"下一个")可以彼此同时运行。
建议:
如果可以面向 Windows Vista 或更高版本,请考虑改用 SRW 锁:
-
http://msdn.microsoft.com/en-us/library/aa904937%28VS.85%29.aspx
-
http://msdn.microsoft.com/en-us/magazine/cc163405.aspx
虽然我认为 sarnold 的答案是正确的,但我只是想指出 CreateList 中 malloc() 调用中的 sizeof() 调用似乎有一个错误。 我认为应该是:
List *pList = malloc(sizeof(List));
按照你拥有它的方式,你将创建足够的内存来保存指向列表而不是列表结构的指针。 (您可能还希望将返回类型强制转换为 (List*),并在使用它之前将其与 NULL 进行比较。
- 使用一个考虑到std::map中键值的滚动或换行的键
- 有充分的理由在h文件中使用include保护而不是cpp文件吗
- 为什么在保护模式下继承升级不起作用
- 如何在c++中只将键插入到bimap的一侧
- 访问被拒绝后,c++中的故障保护代码
- C++:无法访问声明的受保护成员
- 使用2个键的cpp-stl::优先级队列排序不正确
- 有效地使用std::unordered_map来插入或增加键的值
- 为什么您需要C++头文件的包含保护
- lock_guard是否保护返回值
- C++映射有2个键,这样任何1个键都可以用来获取值
- 如何在GTK程序运行时禁用屏幕保护程序/电源管理/屏幕消隐
- 智能指针作为无序映射键,并通过引用进行比较
- 带有数组键C++的二进制映射
- 如何将部分流作为参数传递
- 使用 GLUT 使用键停止动画?
- 无法添加多个键以映射将结构作为键
- 将 std::set 与基于键的比较器一起使用
- 如何使用 std::variant 打印地图键/值?
- 编辑/删除受保护的注册表键值