[英]IPC through shared memory with atomic_t; is it good for x86?
我有以下代码用于通过共享内存进行进程间通信。 一个进程写入日志,另一个进程从其读取。 一种方法是使用信号量,但这里我使用的是驻留在共享内存中的atomic_t类型的原子标志( log_flag )。 日志( log_data )也被共享。
现在的问题是,这是否适用于x86架构,还是我需要信号量或互斥量? 如果我将log_flag设为非原子怎么办? 鉴于x86具有严格的内存模型和主动缓存一致性,并且没有对指针进行优化,我认为它仍然可以工作吗?
编辑 :请注意,我有一个具有8核的多核处理器,因此在这里忙碌等待没有任何问题!
// Process 1 calls this function
void write_log( void * data, size_t size )
{
while( *log_flag )
;
memcpy( log_data, data, size );
*log_flag = 1;
}
// Process 2 calls this function
void read_log( void * data, size_t size )
{
while( !( *log_flag ) )
;
memcpy( data, log_data, size );
*log_flag = 0;
}
您可能需要在循环中使用以下宏,以避免增加内存总线的压力:
#if defined(__x86_64) || defined(__i386)
#define cpu_relax() __asm__("pause":::"memory")
#else
#define cpu_relax() __asm__("":::"memory")
#endif
此外,它还充当内存屏障( "memory"
参数),因此无需将log_flag
声明为volatile
。
但是我认为这太过分了,应该只对硬实时内容执行。 使用futex应该没问题。 也许您可以简单地使用管道,它几乎可以满足所有用途的需求。
我不建议这样做有两个原因:首先,尽管编译器可能无法优化指针访问,但这并不意味着处理器不会缓存该指向的值。 其次,它是原子的事实不会阻止while循环的末尾与执行* log_flag = 0的行之间的读取访问。 互斥锁更安全,但速度要慢得多。
如果您使用的是pthread,请考虑使用RW互斥锁来保护整个缓冲区,这样就不需要标记来对其进行控制,互斥锁本身就是该标记,并且在进行频繁读取时会具有更好的性能。
我也不建议执行空的while()循环,那样会占用所有处理器。 将usleep(1000)放入循环中,使处理器有机会呼吸。
有很多原因导致您应该使用信号量而不依赖标志。
问题2可能看起来很可能很少出现,并且很难找到问题所在。 因此,请帮自己一个忙,并使用正确的操作系统原语。 他们将保证一切正常。
只要log_flag
是原子的,就可以了。
如果log_flag
只是常规布尔值,则不能保证它会起作用。
编译器可能会重新排序您的指令
*log_flag = 1;
memcpy( log_data, data, size );
这在单处理器系统上在语义上是相同的,只要未在memcpy
内部访问log_flag
即可。 您唯一可以节省的宽限可能是劣质的优化程序,它无法推断出在memcpy
中访问了哪些变量。
CPU可以重新排序您的指令
它可以选择在循环之前加载log_flag以优化管道。
缓存可能会重新排序您的内存写入。
包含log_flag
的缓存行可能会在包含data
的缓存行之前与其他处理器同步。
您需要的是一种告诉编译器,cpu和缓存“递归”的方法,以使他们不必对顺序进行假设。 那只能用内存栅栏来完成。 std::atomic
, std::mutex
和semaphore均在其代码中嵌入了正确的内存防护指令。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.