【发布时间】:2013-12-17 02:12:57
【问题描述】:
我在 C 中有一个哈希表实现,其中表中的每个位置都是一个链表(用于处理冲突)。这些链表本质上是线程安全的,因此如果哈希表的大小是恒定的,则不需要在哈希表级别编写额外的线程安全代码 - 哈希表是线程安全的。
但是,我希望哈希表在添加值时动态扩展,以保持合理的访问时间。但是,要扩展表格,它需要额外的线程安全性。
就本问题而言,可以安全地同时发生的过程是“良性的”,而表大小调整过程(不能同时发生)是“关键的”。当前使用该列表的线程称为“用户”。
我对此的第一个解决方案是为所有关键功能放置“前导”和“后置”代码,这些功能会锁定互斥锁,然后等待直到没有当前用户继续操作。然后我在良性函数中添加了前导和后导代码,以检查是否有关键函数正在等待,如果是,则在同一个互斥体处等待,直到关键部分完成。
在伪代码中,前导/后导函数应该如下所示:
benignPreamble(table) {
if (table->criticalIsRunning) {
waitUntilSignal;
}
incrementUserCount(table);
}
benignPostamble(table) {
decrementUserCount(table);
}
criticalPreamble(table) {
table->criticalIsRunning = YES;
waitUntilZero(table->users);
}
criticalPostamble(table) {
table->criticalIsRunning = NO;
signalCriticalDone();
}
我的实际代码显示在这个问题的底部,并使用(可能是不必要的)caf's PriorityLock from this SO question。我的实现,坦率地说,smells awful。有什么更好的方法来处理这种情况?目前我正在寻找一种方法来向互斥体发出信号,表明它是不相关的并同时“解锁所有等待的线程”,但我一直认为必须有一种更简单的方法。我正在尝试以这样一种方式对其进行编码,即如果关键进程未运行,则任何线程安全机制都将被“忽略”。
当前代码
void startBenign(HashTable *table) {
// Ignores if critical process can't be running (users >= 1)
if (table->users == 0) {
// Blocks if critical process is running
PriorityLockLockLow(&(table->lock));
PriorityLockUnlockLow(&(table->lock));
}
__sync_add_and_fetch(&(table->users), 1);
}
void endBenign(HashTable *table) {
// Decrement user count (baseline is 1)
__sync_sub_and_fetch(&(table->users), 1);
}
int startCritical(HashTable *table) {
// Get the lock
PriorityLockLockHigh(&(table->lock));
// Decrement user count BELOW baseline (1) to hit zero eventually
__sync_sub_and_fetch(&(table->users), 1);
// Wait for all concurrent threads to finish
while (table->users != 0) {
usleep(1);
}
// Once we have zero users (any new ones will be
// held at the lock) we can proceed.
return 0;
}
void endCritical(HashTable *table) {
// Increment back to baseline of 1
__sync_add_and_fetch(&(table->users), 1);
// Unlock
PriorityLockUnlockHigh(&(table->lock));
}
【问题讨论】:
-
互斥锁被删除且线程正在等待时,互斥锁等待函数是否返回特殊状态?
标签: c multithreading pthreads mutex