我有一个生产者一个消费者模型,我需要生产者在数据可用时设置一个标志。我怀疑我可以在没有锁定共享标志的情况下离开,因为:
所以我的问题是,我该如何实现呢?我对volatile关键字的理解,以及像__sync_synchronize()这样的事情充其量是微不足道的,所以假设我知之甚少。具体来说,我希望能够确保在另一个线程中及时看到对该标志的更改。
编辑:我在Linux上使用GCC。
答案 0 :(得分:1)
使用两个变量:
volatile size_t elements_produced; // producer increments it when data is available
volatile size_t elements_consumed; // consumer increments it
elements_produced != elements_consumed
时,
新数据正好可用。 如果你需要无限量,那么另外在更新时修改它。
produce(...) {
elements_produced = (elements_produced + 1) % (max_elements_in_queue + 1);
}
consume(...) {
elements_consumed = (elements_consumed + 1) % (max_elements_in_queue + 1);
}
不需要锁或原子。
这是单生成器,单用户循环环缓冲区的标准实现。
答案 1 :(得分:0)
原子操作意味着(永远如此简单地)阻止其他原子操作,直到完成第一个操作。
我假设我们正在谈论线程,因此我们应该考虑互斥体(但这也适用于进程和信号量)。可以检查(读取)互斥锁(或信号量)而不尝试获取锁定。
如果互斥锁(信号量)的状态是已经锁定,请继续执行其他操作,稍后再试。
答案 2 :(得分:0)
实际上不可能以便携的方式做到这一点。
但是,您可以使用各种编译器内在函数来实现它。
例如,对于x86(-64)上的gcc,可能至少是ARM:
static int queued_work;
static void inc_queued_work()
{
(void)__sync_add_and_fetch( &queued_work, 1 );
}
/*
Decrement queued_work if > 0.
Returns 1 if queued_work was non-equal to 0 before
this function was called.
*/
static int dec_queued_work()
{
/* Read current value and subtract 1.
If the result is equal to -1, add 1 back and return 0.
*/
if( __sync_sub_and_fetch( &queued_work, 1 ) == -1 )
{
__sync_fetch_and_add( &queued_work, 1 );
return 0;
}
return 1;
}
某些CPU:仅支持compare_and_swap。 您也可以使用该内在函数实现此目的:
/* Alternative solution using compare_and_swap */
void inc_queued_work()
{
do {
int queued = queued_work;
/* Try to write queued-1 to the variable. */
if( __sync_bool_compare_and_swap( &queued_work,
queued, queued+1 ) )
return;
} while( 1 );
}
int dec_queued_work()
{
do {
int queued = queued_work;
if( !queued ) return 0;
/* Try to write queued-1 to the variable. */
if( __sync_bool_compare_and_swap( &queued_work,
queued, queued-1 ) )
return queued;
} while( 1 );
}
即使您有多个作家和读者,这些功能也应该有效。 将Google与朋友应用到'sync_add_and_fetch'将为您提供大量参考文档
答案 3 :(得分:-1)
没有锁定,两个线程将永远不会同步,并且消费者将永远旋转等待永远不会改变的值(因为该值被缓存,因此内存put / fetch将永远不会发生)。
总而言之,你必须a)确保从生产者那里写入内存,并且b)确保消费者读取内存。这正是锁的作用,这就是你应该使用它们的原因。如果您的死机设置为锁定,则可以使用睡眠等功能,这些功能可以在唤醒后保证缓存状态。