Usually for memory that is accessed by multi-thread, we would use mutex to lock it. But seems below logic is OK without mutex, but not sure if race condition or potential issue would happen for below pseudo code without mutex lock.
通常对于多线程访问的内存,我们会使用互斥锁来锁定它。但似乎低于逻辑是没有互斥的,但不确定是否会发生竞争条件或潜在问题,如果没有互斥锁,下面的伪代码会发生。
queue q;
int thread_read(){
if(!q.empty())
a = q.front();
q.pop();
}
int thread_write(b){
if(!q.full())
p.push(b)
}
2 个解决方案
#1
0
Unless the queue uses a mutex (or something at least vaguely similar such as memory fences, atomic variables, etc.), yes, this could easily have a problem.
除非队列使用互斥锁(或至少模糊相似的东西,如内存栅栏,原子变量等),是的,这可能很容易出问题。
Just for example, let's assume a queue
defined to use some (single) variable to hold how much space is currently available in the queue. So, your push
and pop
have code something like:
例如,让我们假设一个队列被定义为使用某个(单个)变量来保存队列中当前可用的空间。所以,你的推送和弹出代码类似于:
push(item) {
--space_avail;
// ...
}
pop() {
++space_avail;
}
When written like this, the problem may not be obvious, so let's look at what kind of code we might expect to see:
如果这样编写,问题可能并不明显,那么让我们看一下我们可能期望看到的代码类型:
// --space_avail
mov r0, space_avail
dec r0
mov space_avail, r0
// ++ space_avail
mov r0, space_avail
inc r0
mov space_avail, r0
Now the problem is probably more apparent. If our produce and consumer threads overlap like this:
现在问题可能更明显了。如果我们的产品和消费者线程重叠如下:
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
If we do a push and a pop, we expect space_avail
to end up with the same value it started with--but in this case, it doesn't; it comes out one larger than it started out. You can probably also pretty easily see where swapping the dec/store sequence and the inc/store sequence would reverse that, so space_avail
would come out smaller than it started.
如果我们进行推送和弹出,我们希望space_avail最终得到它开头的相同值 - 但在这种情况下,它不会;它出来的比它开始的要大。你也可以很容易地看到交换dec / store序列的位置和inc / store序列会反转,所以space_avail会比它开始时更小。
Clearly either of these leads to a queue that doesn't work corectly.
显然,这些中的任何一个都会导致队列无法正常工作。
#2
0
NO
没有
First, queue::full is not a part of std, so if you're using a custom queue, we can't answer that question without knowing the internal implementation.
首先,queue :: full不是std的一部分,因此如果你使用的是自定义队列,我们就无法在不知道内部实现的情况下回答这个问题。
Second, in your pseudo code, if the queue has for example 1 item in it, and hypothetical size is 8, both conditions will be satisfied and both will enter their logic. Despite your naming of the methods, both functions perform a write operation, because both queue::pop and queue::push changes the state of the queue object.
其次,在您的伪代码中,如果队列中有例如1个项目,并且假设大小为8,则两个条件都将得到满足,并且两个条件都将进入其逻辑。尽管您对方法进行了命名,但两个函数都执行写操作,因为queue :: pop和queue :: push都会更改队列对象的状态。
And if two concurrent threads modify a single object, you always has to use mutex to ensure consistency of data.
如果两个并发线程修改单个对象,则始终必须使用互斥锁来确保数据的一致性。
#1
0
Unless the queue uses a mutex (or something at least vaguely similar such as memory fences, atomic variables, etc.), yes, this could easily have a problem.
除非队列使用互斥锁(或至少模糊相似的东西,如内存栅栏,原子变量等),是的,这可能很容易出问题。
Just for example, let's assume a queue
defined to use some (single) variable to hold how much space is currently available in the queue. So, your push
and pop
have code something like:
例如,让我们假设一个队列被定义为使用某个(单个)变量来保存队列中当前可用的空间。所以,你的推送和弹出代码类似于:
push(item) {
--space_avail;
// ...
}
pop() {
++space_avail;
}
When written like this, the problem may not be obvious, so let's look at what kind of code we might expect to see:
如果这样编写,问题可能并不明显,那么让我们看一下我们可能期望看到的代码类型:
// --space_avail
mov r0, space_avail
dec r0
mov space_avail, r0
// ++ space_avail
mov r0, space_avail
inc r0
mov space_avail, r0
Now the problem is probably more apparent. If our produce and consumer threads overlap like this:
现在问题可能更明显了。如果我们的产品和消费者线程重叠如下:
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
If we do a push and a pop, we expect space_avail
to end up with the same value it started with--but in this case, it doesn't; it comes out one larger than it started out. You can probably also pretty easily see where swapping the dec/store sequence and the inc/store sequence would reverse that, so space_avail
would come out smaller than it started.
如果我们进行推送和弹出,我们希望space_avail最终得到它开头的相同值 - 但在这种情况下,它不会;它出来的比它开始的要大。你也可以很容易地看到交换dec / store序列的位置和inc / store序列会反转,所以space_avail会比它开始时更小。
Clearly either of these leads to a queue that doesn't work corectly.
显然,这些中的任何一个都会导致队列无法正常工作。
#2
0
NO
没有
First, queue::full is not a part of std, so if you're using a custom queue, we can't answer that question without knowing the internal implementation.
首先,queue :: full不是std的一部分,因此如果你使用的是自定义队列,我们就无法在不知道内部实现的情况下回答这个问题。
Second, in your pseudo code, if the queue has for example 1 item in it, and hypothetical size is 8, both conditions will be satisfied and both will enter their logic. Despite your naming of the methods, both functions perform a write operation, because both queue::pop and queue::push changes the state of the queue object.
其次,在您的伪代码中,如果队列中有例如1个项目,并且假设大小为8,则两个条件都将得到满足,并且两个条件都将进入其逻辑。尽管您对方法进行了命名,但两个函数都执行写操作,因为queue :: pop和queue :: push都会更改队列对象的状态。
And if two concurrent threads modify a single object, you always has to use mutex to ensure consistency of data.
如果两个并发线程修改单个对象,则始终必须使用互斥锁来确保数据的一致性。