以原子方式交换两个指针的值

发布于 2025-01-16 16:29:20 字数 1582 浏览 2 评论 0原文

我了解到信号量可以充当原子锁,可以执行两个功能:downup

有什么办法可以原子地交换两个指针的值,避免竞争条件和死锁。

我首先提出了“解决方案”,假设两个指针都有:

Item a = { value = "A", lock = Semaphore(1) }
Item b = { value = "B", lock = Semaphore(1) }

void atomic_swap(Item* a, Item* b) {
    a->lock.down(); // acquire
    b->lock.down(); // acquire
    
    non_atomic_swap(&a.value, &b.value);

    b->lock.up(); // release
    a->lock.up(); // release
}

但如果我没有错的话,如果使用相同的指针调用两个 atomic_swap ,则会导致死锁:例如。

Item a = ...;
Item b = ...;
thread_start(atomic_swap, {&a, &b}); // start a thread running atomic_swap(&a, &b);
thread_start(atomic_swap, {&b, &a}); // start a thread running atomic_swap(&b, &a);

在上面的代码中,如果对 atomic_swap 的调用同时到达第一个 down,则下一个 down 将永远阻塞,从而导致死锁。


我能想到的避免死锁的解决方案之一是为它们分配一个“组”,只有同一组中的项目才能安全地执行atomic_swap(没有死锁):

Group g = { lock = Semaphore(1) };
Item a = { value = "A", group = g };
Item b = { value = "B", group = g };

void atomic_swap(Item* a, Item* b) {
    // assume a->group == b->group

    a->group.down() // b->group.down()
    non_atomic_swap(&a.value, &b.value);
    a->group.up(); // b->group.up();
}

但这当然要求每个项目都携带一个,不相关的项目可能会因为其他调用而等待该组。

理论上有什么好的方法可以使用信号量执行atomic_swap吗?

I've learnt that semaphore can act as an atomic lock that can perform two function: down and up.

Is there any way, to swap the value of two pointers atomically, avoiding race condition and deadlock.

I first came up with the 'solution', suppose both pointers has :

Item a = { value = "A", lock = Semaphore(1) }
Item b = { value = "B", lock = Semaphore(1) }

void atomic_swap(Item* a, Item* b) {
    a->lock.down(); // acquire
    b->lock.down(); // acquire
    
    non_atomic_swap(&a.value, &b.value);

    b->lock.up(); // release
    a->lock.up(); // release
}

But if I am not wrong, it will result to deadlock if two atomic_swap is called using same pointers: eg.

Item a = ...;
Item b = ...;
thread_start(atomic_swap, {&a, &b}); // start a thread running atomic_swap(&a, &b);
thread_start(atomic_swap, {&b, &a}); // start a thread running atomic_swap(&b, &a);

On the code above, if both call to atomic_swap arrive the first down simultaneously, the next down will block forever, which results to deadlock.


One of the solution I can think about to avoid deadlock is assign a 'group' to them, only item in the same group can perform atomic_swap safely (without deadlock):

Group g = { lock = Semaphore(1) };
Item a = { value = "A", group = g };
Item b = { value = "B", group = g };

void atomic_swap(Item* a, Item* b) {
    // assume a->group == b->group

    a->group.down() // b->group.down()
    non_atomic_swap(&a.value, &b.value);
    a->group.up(); // b->group.up();
}

But this of course require every item to carry a group, and unrelated items might wait for the group because of other calls.

Is there any good way to perform the atomic_swap theoretically using semaphore?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

亣腦蒛氧 2025-01-23 16:29:20

您可以使用 std::less 来比较指针,以确保所有用户以相同的顺序获取锁:

void atomic_swap(Item* a, Item* b) {
    std::less<Item *> cmp;

    if (cmp(a, b)) {
        a->lock.down();
        b->lock.down();
    } else {
        b->lock.down();
        a->lock.down(); }
    
    non_atomic_swap(&a->value, &b->value);

    b->lock.up(); // release
    a->lock.up(); // release
}

You can use std::less to compare the pointers to ensure that all users acquire the locks in the same order:

void atomic_swap(Item* a, Item* b) {
    std::less<Item *> cmp;

    if (cmp(a, b)) {
        a->lock.down();
        b->lock.down();
    } else {
        b->lock.down();
        a->lock.down(); }
    
    non_atomic_swap(&a->value, &b->value);

    b->lock.up(); // release
    a->lock.up(); // release
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文