2015-05-09 80 views
1

我目前正在嘗試實現一個爲給定進程創建共享內存區域的C程序,然後將此進程分叉爲一個子進程,使子進程寫入共享內存的給定位置,讓父親等待,直到孩子寫在那個位置。我使用了一種簡單的忙碌等待方法,讓父進程等待,直到孩子用一個while循環結束他的寫作。問題是隻有當我在該循環中引入一些延遲時才起作用。任何人都知道這是爲什麼?忙碌的等待和共享內存

代碼:

int shmid; 
int *shmptr; 
int i, j, ret; 

key_t key = SHM_KEY; 

// Create shared memory segment 
if ((shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0600)) < 0) 
{ 
    printf("shmget error: %s\n", strerror(errno)); 
    return -1; 
} 

// Attach shared memory segment 
if ((shmptr = shmat(shmid, 0, 0)) == (void *) -1) 
{ 
    puts("shmat error"); 
    return -1; 
} 

shmptr[6] = '%'; 

ret = fork(); 
if (ret > 0) 
{/*parent*/ 
    /*here is the loop that implements the busy waiting approach*/ 
    while (shmptr[6] != '^') { 
     sleep(1); 
    } 
    for (i = 0; i < 7; i++) printf("%c", shmptr[i]); 
    puts(""); 

    int status = 0; 
    wait(&status); 
} 
else 
{/*child*/ 
    shmptr[0] = 's'; 
    shmptr[1] = 'h'; 
    shmptr[2] = 'a'; 
    shmptr[3] = 'r'; 
    shmptr[4] = 'e'; 
    shmptr[5] = 'd'; 

    /*tell parent process ithas finished its writing*/ 
    shmptr[6] = '^'; 

    exit(0); 
} 
+0

如何shmptr聲明?特別是它是不穩定的? – DoxyLover

+0

你能詳細說明你的代碼還是發佈整個代碼? –

+0

「*只有當我在該循環中引入一些延遲時才起作用*」儘管發生什麼事情沒有延遲? – alk

回答

0

你想synchonise訪問共享內存(SHM)。

這個,例如,可以通過使用semphore來完成。

  1. 之前fork()關閉子電話sem_open()
  2. 在閱讀SHM之前讓父母在sem_wait()上等待。
  3. 完成書寫SHM後讓孩子撥打sem_post()
0

我想現在發生的事情是孩子終止得太快。

您可以使用一個非懸掛waitpid(2),並將其添加在你的循環:

/*here is the loop that implements the busy waiting approach*/ 
int status= 0; 
while (shmptr[6] != '^') { 
    if (waitpid(ret, &status, WNOHANG) == ret) break; 
    sleep(1); 
} 

然而,正如我評論,忙等待總是壞的Linux用戶空間程序(至少它強調你的系統)。請閱讀sem_overview(7),或者另外設置pipe(7)eventfd(2)signalfd(2)poll(2)它。或者設置一個SIGCHLD信號處理程序(仔細閱讀​​),它只設置一個要在循環中測試的volatile sigatomic_t標誌。

您還應該聲明volatile int*shmptr;,因爲編譯器可能已經優化了它的使用。

1

易失(請參閱前面的註釋可能僅適用於單核情況)。假設您在具有多個內核的CPU上運行,則需要以原子方式處理共享內存區域中每個位置的訪問權限。如果使用符合C++ 11的編譯器,則需要假定該區域的每個位置都是std::atomic<int>類型。

由於您可能正在使用C而不是C++,並且正在使用GCC,因此請考慮使用原子內置函數GCC Atomic Builtins

所以,你

shmptr[0] = 's'; 

語句應該用原子集合運算符來代替:

_sync_val_compare_and_swap(&shmptr[0], 's'); 

,並做了所有集合的等價物。然後,在循環中執行相同的操作來檢查返回值(這將是您想要的字符)。

另一個答案中的信號可能有效,但不能保證其他位置將通過CPU寫入電路,通過源上的高速緩存控制器等等,通過接收CPU控制器特別是如果正在訪問的地址跨越緩存行。我也建議做某種睡眠(0)或yield(),以允許其他程序在運行主程序的核心上獲得時間片,否則,會浪費CPU資源。