【问题标题】:Signalling to threads waiting at a lock that the lock has become irrelevant向在锁处等待的线程发出信号通知该锁已变得无关紧要
【发布时间】: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


【解决方案1】:

看起来您正在尝试重新发明读写器锁,我相信 pthreads 将其作为原语提供。你试过用那个吗?

更具体地说,您的良性功能应该使用“读取器”锁,而您的关键功能需要“写入器”锁。最终结果将是尽可能多的良性函数可以根据需要执行,但是当一个关键函数开始执行时,它会等到没有良性函数在运行,并且会阻止其他良性函数直到它完成。我想这就是你想要的。

【讨论】:

    猜你喜欢
    • 2013-07-22
    • 1970-01-01
    • 2019-04-29
    • 2017-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-24
    相关资源
    最近更新 更多