[英]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.