簡體   English   中英

C Linux pthreads:使用共享內存將數據從一個線程發送到另一個線程會產生意外結果

[英]C Linux pthreads: sending data from one thread to another using shared memory gives unexpected result

我正在編寫一個程序,它將使用共享內存將50個整數從一個線程傳輸到另一個線程,並且在接收到整數后,接收方線程將打印它們。

代碼編譯時沒有任何錯誤或警告,但是當我運行它時,得到以下輸出:

pthread_create() for thread 1 returns: 0
pthread_create() for thread 2 returns: 0
Segmentation fault (core dumped)

到目前為止,這是我的代碼:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/msg.h>
#include <string.h>

//define declarations
#define SIZE     50

//function declarations
void *send_data();
void *receive_data();

int main()
{
     pthread_t thread1;
     pthread_t thread2;
     int ret_val_t1;
     int ret_val_t2;

     //create thread1
     ret_val_t1 = pthread_create( &thread1, NULL, send_data, NULL);
     if(ret_val_t1)
     {
         fprintf(stderr,"Error - pthread_create() return value: %d\n",ret_val_t1);
         exit(EXIT_FAILURE);
     }

     //create thread2
     ret_val_t2 = pthread_create( &thread2, NULL, receive_data, NULL);
     if(ret_val_t2)
     {
         fprintf(stderr,"Error - pthread_create() return value: %d\n",ret_val_t2);
         exit(EXIT_FAILURE);
     }

     printf("pthread_create() for thread 1 returns: %d\n",ret_val_t1);
     printf("pthread_create() for thread 2 returns: %d\n",ret_val_t2);

     //wait untill threads are done with their routines before continuing with main thread
     pthread_join( thread1, NULL);
     pthread_join( thread2, NULL); 

     exit(EXIT_SUCCESS);
}

void *send_data(){
        int shmid;
    int *array;
    int i = 0;
    int SizeMem;
    key_t key = 12345;

    SizeMem = sizeof(*array)*SIZE;

    shmid = shmget(key, SIZE*sizeof(int), IPC_CREAT);

    array = (int *)shmat(shmid, 0, 0);


    for(i=0; i<SIZE; i++)
    {
          array[i] = i;
    }

    for(i=0; i<SIZE; i++)
    {
            printf("\n%d---\n", array[i]);
    }

    printf("\nWritting to memory succesful--\n");

    shmdt((void *) array);
}

void *receive_data(){
    int shmid;
    int *array;
    int i = 0;
    key_t key = 12345;

    shmid = shmget(key, SIZE*sizeof(int), IPC_EXCL);

    array = shmat(shmid, 0, SHM_RDONLY);

    for(i=0; i<SIZE; i++)
        {
            printf("\n%d---\n", array[i]);
        }

        printf("\nRead to memory succesful--\n");

        shmdt((void *) array);
}

在這種情況下,共享內存是一項昂貴的事務。 而且,您嘗試通過同一過程進行訪問,這沒有任何好處。

處理您的情況的更好方法是:

父進程的線程將有權訪問父進程堆內存。 這是使用簡單的概念。 為父進程創建一個堆對象,並在線程之間共享。

如許多評論中所述,共享內存是“進程間通信”通信概念之一,例如管道或命名管道或消息隊列等。

如果您用於練習,那就可以了。 但是,除了使用PROD之外,這是一項昂貴的事務。

如果您沒有對映射/共享的內存正確地應用鎖定和訪問限制,並且您沒有受到安全防火牆的保護,那么您就是在歡迎攻擊者。

一種競爭條件源於您的代碼。 您的第二個線程可以先獲取CPU,然后嘗試使用尚未創建的內存段。 由於它不存在,並且您不檢查錯誤,因此可以通過嘗試訪問NULL地址的內存來獲取SIGSEGV

您必須放置禁止第二個線程進入共享內存訪問的同步設備,然后再創建它並填充數據。 就像是。

pthread_mutex_t lock;
pthread_cond_t shm_created_and_filled;

然后在main初始化lockshm_created_and_filled

在寫入線程中,您將創建共享內存段並寫入數字,最后鎖定shm_created_and_filled信號shm_created_and_filled條件變量。 在閱讀線程中,您首先鎖定lock變量,然后等待shm_created_and_filled條件。 在讀取線程等待它之前,還有一個競爭條件,其中第一個線程運行並向shm_created_and_filled條件發出信號(它將丟失該條件),但我將其作為練習留給了讀者。

使用ipcs實用程序並查看ipcs -m的輸出

根據shmget手冊頁

內容提要

  #include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, size_t size, int shmflg); 

...

除了上述標志之外,shmflg的最低有效9位還指定了授予所有者,組和其他人的權限 這些位與open(2)的mode參數具有相同的格式和相同的含義。 當前,系統未使用執行權限。

符合代碼

shmid = shmget(key, SIZE*sizeof(int), IPC_CREAT);

“ shmflg的最低有效9位”設置為零。

沒有人有權讀取/寫入您的共享內存段。

這樣會更好:

shmid = shmget(key, SIZE*sizeof(int), IPC_CREAT | 0600 );

這將為擁有用戶提供讀/寫權限。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM