通过atomic_t共享内存实现IPC;它适合x86吗?
IPC through shared memory with atomic_t; is it good for x86?
我有以下代码通过共享内存进行进程间通信。一个进程写日志,另一个进程读日志。一种方法是使用信号量,但是这里我使用的是类型为atomic_t的原子标志(log_flag),它位于共享内存中。日志(log_data)也是共享的。
现在的问题是,这是否适用于x86架构,或者我是否需要信号量或互斥体?如果我使log_flag非原子的呢?鉴于x86具有严格的内存模型和主动缓存一致性,并且没有对指针应用优化,我认为它仍然有效?
EDIT:请注意,我有一个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的行之间的读访问。互斥锁更安全,尽管速度要慢得多。
如果你使用pthreads,考虑使用RW互斥锁来保护整个缓冲区,这样你就不需要一个标志来控制它,互斥锁本身就是一个标志,当你频繁读取时,你会有更好的性能。
我也不建议使用空的while()循环,那样会占用所有的处理器空间。在循环中放置一个ussleep(1000),给处理器一个喘息的机会。
应该使用信号量而不是依赖标志的原因有很多。
- 你的读日志while循环不必要地旋转。这会不必要地消耗系统资源,比如电力。这也意味着CPU不能用于其他任务。 如果x86完全保证读写顺序,我会感到惊讶。输入数据可以将日志标志设置为1,而输出数据可以将其设置为0。这可能意味着你最终会丢失数据。
- 我不知道你从哪里得到的优化不应用于指针作为一般用途。优化可以应用于任何与外部变化没有区别的地方。编译器可能不知道log_flag可以被并发进程改变。
问题2可能很可能很少出现,并且很难追踪到问题。所以帮你自己一个忙,使用正确的操作系统原语。他们会保证事情按预期进行。
只要log_flag
是原子,你就会没事的。
如果log_flag
只是一个普通bool,你不能保证它会工作。
编译器可以重新排序你的指令
*log_flag = 1;
memcpy( log_data, data, size );
在单处理器系统上,只要log_flag
不在memcpy
中被访问,这在语义上是相同的。您唯一的可取之处可能是一个较差的优化器,它不能推断出memcpy
中访问了哪些变量。
cpu可以重新排序你的指令
它可以选择在循环之前加载log_flag来优化管道。
缓存可能会重新排序内存写入。
包含log_flag
的缓存行可能会在包含data
的缓存行之前同步到其他处理器。
你需要的是一种告诉编译器、cpu和缓存"放手"的方法,这样它们就不会对顺序做出假设。这只能通过记忆栅栏来实现。std::atomic
、std::mutex
和信号量都在它们的代码中嵌入了正确的内存栅栏指令。
- IPC使用多个管道和分支进程来运行Python程序
- 为x86而非x64编译时出错
- C++如何仅使用MOV在x86上实现发布和获取
- 我们可以通过 IPC 传递具有动态管理成员的类对象吗?
- 在 c++ 中使用 x86 DIV 的这个 asm 块有什么用?
- 在 QNX 中,如何管理服务器和客户端之间的 IPC 连接?
- 在 x86 上实现 std::atomic_thread_fence(std::memory_order_seq_cst
- 如何将C++子例程链接到 x86 程序集程序?
- 如何在 x86 处理器上实现"锁定添加"
- 您选择的 CPU 不支持 x86-64 指令集
- std::x86 上需要memory_order_acquire围栏吗?
- 在C++和 Python 程序中使用命名管道的 IPC 挂起
- 尝试使用 x86 asm SSSE3 将大端转换为小端序
- 如何在 MSVC C++中迁移 x64 的 x86 代码
- 将内联程序集尾调用函数尾声替换为用于x86/x64 msvc的Intrinsics
- 使用IPC/共享内存将Integer数组从C++传递到Python
- 将程序从x86转换为x64
- 如果由不同的线程写入 8 字节,那么现代英特尔 x86 上的 8 字节读取是否保证理智?
- 将vector<vector<double>>从x86平台中创建的一个进程发送到x64中构建的另一个进程的最快方法是什么
- 通过atomic_t共享内存实现IPC;它适合x86吗?