【问题标题】:would queue.empty() and queue.full() guarantee thread safe if I only 1 read thread and 1 write thread?如果我只有 1 个读线程和 1 个写线程, queue.empty() 和 queue.full() 会保证线程安全吗?
【发布时间】:2018-07-13 21:57:51
【问题描述】:

通常对于多线程访问的内存,我们会使用互斥锁来锁定它。 但似乎没有互斥锁,下面的逻辑是可以的,但不确定下面没有互斥锁的伪代码是否会发生竞争条件或潜在问题。

queue q;
int thread_read(){
    if(!q.empty())
       a = q.front();
       q.pop();
}

int thread_write(b){
    if(!q.full())
       p.push(b)
}

【问题讨论】:

  • 问多线程问题时,贴出真实代码。
  • std::queue 适配器上没有“完整”方法,所以您使用的是其他方法吗?对象访问者的交错使得单独的锁定成为第二优先事项。仅供参考,std::queue 是一个适配器,并包含一个模板参数化的序列容器(默认为std::deque)。与标准库中的所有其他容器一样,它也保证对于 volatile 并发的线程安全。
  • 您也不希望库容器是线程安全的。为所有用户获得正确的同步粒度是不可能的,因此您不妨将其排除在外,让用户根据他们的需要在包装器中进行同步。 Java 在几年前就遇到了他们的库 Vector
  • 本来想自己实现full()函数,后来发现full()和empty()需要counter来判断是空还是满,而这个counter也需要受互斥体保护。所以在没有 mutext 的情况下使用 full() 并不是一个好方法。

标签: c++ multithreading queue mutex shared-memory


【解决方案1】:

除非队列使用互斥体(或至少有点类似的东西,例如内存栅栏、原子变量等),是的,这很容易出现问题。

例如,假设queue 定义为使用某个(单个)变量来保存队列中当前可用的空间量。所以,你的 pushpop 有类似这样的代码:

push(item) {
    --space_avail;
    // ...
}

pop() {
    ++space_avail;
}

这样写,问题可能不明显,那么我们看看我们可能期望看到什么样的代码:

// --space_avail
mov r0, space_avail
dec r0
mov space_avail, r0

// ++ space_avail
mov r0, space_avail
inc r0
mov space_avail, r0

现在问题可能更明显了。如果我们的生产线程和消费者线程像这样重叠:

T0: mov r0, space avail
T1: mov r0, space_avail
T1: dec r0
T1: mov space_avail, r0
T0: inc r0
T0: mov space_avail, r0

如果我们执行推送和弹出操作,我们希望 space_avail 以与开始时相同的值结束——但在这种情况下,它不会;它比开始时大一号。您可能还可以很容易地看到在哪里交换 dec/store 序列和 inc/store 序列会反转它,所以space_avail 会比它开始时更小。

显然,其中任何一个都会导致无法正常工作的队列。

【讨论】:

    【解决方案2】:

    首先,queue::full 不是 std 的一部分,所以如果您使用自定义队列,我们​​无法在不了解内部实现的情况下回答这个问题。

    其次,在您的伪代码中,如果队列中有例如 1 个项目,并且假设大小为 8,则两个条件都将满足并且都将进入它们的逻辑。尽管您对方法进行了命名,但这两个函数都执行写操作,因为 queue::pop 和 queue::push 都会更改队列对象的状态。

    如果两个并发线程修改一个对象,你总是必须使用互斥锁来确保数据的一致性。

    【讨论】:

    • 本来想自己实现full()函数,后来发现full()和empty()需要counter来判断是空还是满,而这个counter也需要受互斥体保护。所以在没有 mutext 的情况下使用 full() 并不是一个好方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-15
    • 2012-08-18
    • 2015-04-18
    • 1970-01-01
    相关资源
    最近更新 更多