一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Linux進程間共享內(nèi)存通信時如何同步?

CHANBAEK ? 來源:Linux兵工廠 ? 作者:YuLinMuRon ? 2023-05-11 18:25 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

嗨嘍!大家好!我是 木榮 。

今天我們來講講進程間使用共享內(nèi)存通信時為了確保數(shù)據(jù)的正確,如何進行同步?

Linux中,進程間的共享內(nèi)存通信需要通過同步機制來保證數(shù)據(jù)的正確性和一致性,常用的同步機制包括信號、互斥鎖條件變量等。

其中,使用信號量來同步進程間的共享內(nèi)存訪問是一種常見的方法。每個共享內(nèi)存區(qū)域可以關(guān)聯(lián)一個或多個信號量,以保護共享內(nèi)存區(qū)域的讀寫操作。在訪問共享內(nèi)存之前,進程需要獲取信號量的使用權(quán),當完成讀寫操作后,再釋放信號量的使用權(quán),以便其他進程可以訪問共享內(nèi)存區(qū)域。

1、信號量同步

下面是一個簡單的示例程序,展示了如何使用信號量來同步共享內(nèi)存區(qū)域的讀寫操作:

#include 
#include 
#include 
#include 
#include 
#include 

#define SHM_SIZE 1024
#define SEM_KEY 0x123456

// 定義聯(lián)合體,用于信號量操作
union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

int main() {
    int shmid, semid;
    char *shmaddr;
    struct sembuf semops[2];
    union semun semarg;

    // 創(chuàng)建共享內(nèi)存區(qū)域
    shmid = shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0666);
    if (shmid == -1) {
        perror("shmget");
        exit(1);
    }

    // 將共享內(nèi)存區(qū)域附加到進程地址空間中
    shmaddr = shmat(shmid, NULL, 0);
    if (shmaddr == (char *) -1) {
        perror("shmat");
        exit(1);
    }

    // 創(chuàng)建信號量
    semid = semget(SEM_KEY, 1, IPC_CREAT | 0666);
    if (semid == -1) {
        perror("semget");
        exit(1);
    }

    // 初始化信號量值為1
    semarg.val = 1;
    if (semctl(semid, 0, SETVAL, semarg) == -1) {
        perror("semctl");
        exit(1);
    }

    // 等待信號量
    semops[0].sem_num = 0;
    semops[0].sem_op = 0;
    semops[0].sem_flg = 0;
    if (semop(semid, semops, 1) == -1) {
        perror("semop");
        exit(1);
    }

    // 在共享內(nèi)存中寫入數(shù)據(jù)
    strncpy(shmaddr, "Hello, world!", SHM_SIZE);

    // 釋放信號量
    semops[0].sem_num = 0;
    semops[0].sem_op = 1;
    semops[0].sem_flg = 0;
    if (semop(semid, semops, 1) == -1) {
        perror("semop");
        exit(1);
    }

    // 等待信號量
    semops[0].sem_num = 0;
    semops[0].sem_op = 0;
    semops[0].sem_flg = 0;
    if (semop(semid, semops, 1) == -1) {
        perror("semop");
        exit(1);
    }

    // 從共享內(nèi)存中讀取數(shù)據(jù)
    printf("Received message: %s\\n", shmaddr);

    // 釋放共享內(nèi)存區(qū)域
    if (shmdt(shmaddr) == -1) {
        perror("shmdt");
        exit(1);
    }

    // 刪除共享內(nèi)存區(qū)域
    if (shmctl(shmid, IPC_RMID, NULL) == -1) {
        perror("shmctl");
        exit(1);
    }

    // 刪除信號量
    if (semctl(semid, 0, IPC_RMID, semarg) == -1) {
        perror("semctl");
        exit(1);
    }

    return 0;

在這個示例程序中,使用了System V信號量來同步共享內(nèi)存的讀寫操作。程序首先創(chuàng)建一個共享內(nèi)存區(qū)域,并將其附加到進程地址空間中。然后,使用semget()函數(shù)創(chuàng)建一個信號量,并將其初始化為1。在寫入共享內(nèi)存數(shù)據(jù)之前,程序使用semop()函數(shù)等待信號量。一旦獲取了信號量的使用權(quán),程序就可以在共享內(nèi)存區(qū)域中寫入數(shù)據(jù)。寫入數(shù)據(jù)完成后,程序再次使用semop()函數(shù)釋放信號量的使用權(quán)。在讀取共享內(nèi)存數(shù)據(jù)時,程序同樣需要等待信號量的使用權(quán),讀取數(shù)據(jù)完成后,再次釋放信號量的使用權(quán)。

需要注意的是,使用信號量來同步共享內(nèi)存訪問時,需要確保每個進程都按照一定的順序進行讀寫操作。否則,就可能出現(xiàn)死鎖等問題。因此,在設計進程間共享內(nèi)存通信時,需要仔細考慮數(shù)據(jù)的讀寫順序,并采取合適的同步機制來確保數(shù)據(jù)的正確性和一致性。

2、互斥鎖同步

互斥量也是一種常用的同步機制,可以用來實現(xiàn)多個進程之間的共享內(nèi)存訪問。在Linux中,可以使用pthread庫中的互斥量來實現(xiàn)進程間共享內(nèi)存的同步。

下面是一個使用互斥量實現(xiàn)共享內(nèi)存同步的示例程序:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define SHM_SIZE 1024

// 共享內(nèi)存結(jié)構(gòu)體
typedef struct {
    pthread_mutex_t mutex;
    char data[SHM_SIZE];
} shm_data_t;

int main() {
    int fd;
    shm_data_t *shm_data;
    pthread_mutexattr_t mutex_attr;
    pthread_mutex_t *mutex;
    
    // 打開共享內(nèi)存文件
    if ((fd = shm_open("/my_shm", O_CREAT | O_RDWR, 0666)) == -1) {
        perror("shm_open");
        exit(1);
    }

    // 調(diào)整共享內(nèi)存文件大小
    if (ftruncate(fd, sizeof(shm_data_t)) == -1) {
        perror("ftruncate");
        exit(1);
    }

    // 將共享內(nèi)存映射到進程地址空間中
    if ((shm_data = mmap(NULL, sizeof(shm_data_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
        perror("mmap");
        exit(1);
    }

    // 初始化互斥量屬性
    pthread_mutexattr_init(&mutex_attr);
    pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);

    // 創(chuàng)建互斥量
    mutex = &(shm_data->mutex);
    pthread_mutex_init(mutex, &mutex_attr);

    // 在共享內(nèi)存中寫入數(shù)據(jù)
    pthread_mutex_lock(mutex);
    sprintf(shm_data->data, "Hello, world!");
    pthread_mutex_unlock(mutex);

    // 在共享內(nèi)存中讀取數(shù)據(jù)
    pthread_mutex_lock(mutex);
    printf("Received message: %s\\n", shm_data->data);
    pthread_mutex_unlock(mutex);

    // 解除共享內(nèi)存映射
    if (munmap(shm_data, sizeof(shm_data_t)) == -1) {
        perror("munmap");
        exit(1);
    }

    // 刪除共享內(nèi)存文件
    if (shm_unlink("/my_shm") == -1) {
        perror("shm_unlink");
        exit(1);
    }

    return 0;
}

在這個示例程序中,使用了pthread庫中的互斥量來同步共享內(nèi)存的讀寫操作。程序首先創(chuàng)建一個共享內(nèi)存文件,并將其映射到進程地址空間中。然后,使用pthread_mutex_init()函數(shù)創(chuàng)建一個互斥量,并將其初始化為共享內(nèi)存中的一部分。在寫入共享內(nèi)存數(shù)據(jù)之前,程序使用pthread_mutex_lock()函數(shù)等待互斥量。一旦獲取了互斥量的使用權(quán),程序就可以在共享內(nèi)存區(qū)域中寫入數(shù)據(jù)。寫入數(shù)據(jù)完成后,程序再次使用pthread_mutex_unlock()函數(shù)釋放互斥量的使用權(quán)。在讀取共享內(nèi)存數(shù)據(jù)之前,程序再次使用pthread_mutex_lock()函數(shù)等待互斥量。一旦獲取了互斥量的使用權(quán),程序就可以在共享內(nèi)存區(qū)域中讀取數(shù)據(jù)。讀取數(shù)據(jù)完成后,程序再次使用pthread_mutex_unlock()函數(shù)釋放互斥量的使用權(quán)。最后,程序解除共享內(nèi)存映射,并刪除共享內(nèi)存文件。

使用互斥量來同步共享內(nèi)存訪問有以下幾點注意事項:

1、互斥量需要初始化。在創(chuàng)建互斥量之前,需要使用pthread_mutexattr_init()函數(shù)初始化互斥量屬性,并使用pthread_mutexattr_setpshared()函數(shù)將互斥量屬性設置為PTHREAD_PROCESS_SHARED,以便多個進程可以共享互斥量。

2、在訪問共享內(nèi)存之前,需要使用pthread_mutex_lock()函數(shù)獲取互斥量的使用權(quán)。一旦獲取了互斥量的使用權(quán),程序才能訪問共享內(nèi)存。在完成共享內(nèi)存的訪問之后,需要使用pthread_mutex_unlock()函數(shù)釋放互斥量的使用權(quán),以便其他進程可以訪問共享內(nèi)存。

3、互斥量必須存儲在共享內(nèi)存區(qū)域中。在創(chuàng)建互斥量時,需要將其初始化為共享內(nèi)存區(qū)域中的一部分,以便多個進程可以訪問同一個互斥量。

4、程序必須保證互斥量的一致性。多個進程共享同一個互斥量時,必須保證互斥量的一致性。否則,可能會導致多個進程同時訪問共享內(nèi)存區(qū)域,導致數(shù)據(jù)錯誤或者系統(tǒng)崩潰。

總之,使用互斥量來同步共享內(nèi)存訪問可以有效地避免多個進程同時訪問共享內(nèi)存區(qū)域的問題,從而保證數(shù)據(jù)的一致性和程序的穩(wěn)定性。在實際編程中,需要根據(jù)具體的需求選擇不同的同步機制,以保證程序的正確性和效率。

3、條件變量同步

在Linux下,可以使用條件變量(Condition Variable)來實現(xiàn)多進程之間的同步。條件變量通常與互斥量(Mutex)結(jié)合使用,以便在共享內(nèi)存區(qū)域中對數(shù)據(jù)進行同步訪問。

條件變量是一種線程同步機制,用于等待或者通知某個事件的發(fā)生。當某個進程需要等待某個事件發(fā)生時,它可以通過調(diào)用pthread_cond_wait()函數(shù)來阻塞自己,并將互斥量釋放。一旦事件發(fā)生,其他進程就可以通過調(diào)用pthread_cond_signal()或pthread_cond_broadcast()函數(shù)來通知等待線程。等待線程接收到通知后,會重新獲取互斥量,并繼續(xù)執(zhí)行。

在共享內(nèi)存通信中,可以使用條件變量來實現(xiàn)進程之間的同步。具體操作步驟如下:

初始化互斥量和條件變量。在創(chuàng)建共享內(nèi)存之前,需要使用pthread_mutexattr_init()和pthread_condattr_init()函數(shù)分別初始化互斥量屬性和條件變量屬性。然后,需要使用pthread_mutexattr_setpshared()和pthread_condattr_setpshared()函數(shù)將互斥量屬性和條件變量屬性設置為PTHREAD_PROCESS_SHARED,以便多個進程可以共享它們。

等待條件變量。在讀取共享內(nèi)存之前,程序可以使用pthread_cond_wait()函數(shù)等待條件變量。調(diào)用pthread_cond_wait()函數(shù)會自動釋放互斥量,并阻塞當前進程。一旦其他進程發(fā)送信號通知條件變量發(fā)生變化,等待線程就會重新獲得互斥量,并繼續(xù)執(zhí)行。

發(fā)送信號通知條件變量變化。 在向共享內(nèi)存中寫入數(shù)據(jù)之后,程序可以使用pthread_cond_signal()或pthread_cond_broadcast()函數(shù)發(fā)送信號通知條件變量發(fā)生變化。 調(diào)用pthread_cond_signal()函數(shù)會發(fā)送一個信號通知等待線程條件變量發(fā)生變化,而調(diào)用pthread_cond_broadcast()函數(shù)會向所有等待線程發(fā)送信號通知條件變量發(fā)生變化。

使用條件變量來同步共享內(nèi)存訪問有以下幾點注意事項:

1、程序必須使用互斥量來保護共享內(nèi)存。 在使用條件變量之前,程序必須先獲取互斥量的使用權(quán),以便保護共享內(nèi)存區(qū)域中的數(shù)據(jù)不被多個進程同時訪問。

2、程序必須保證條件變量的一致性。 多個進程共享同一個條件變量時,必須保證條件變量的一致性。 否則,可能會導致多個進程同時訪問共享內(nèi)存區(qū)域,導致數(shù)據(jù)錯誤或者系統(tǒng)崩潰。

3、程序必須正確使用條件變量。 在使用條件變量時,需要正確地使用pthread_cond_wait()、pthread_cond_signal()和pthread_cond_broadcast()函數(shù),否則可能會導致死鎖或者其他問題。

4、程序必須正確處理信號。 當調(diào)用pthread_cond_wait()函數(shù)時,程序可能會因為接收到信號而提前返回,此時程序需要正確地處理信號。

下面是一個使用條件變量實現(xiàn)進程間共享內(nèi)存同步的示例代碼:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define SHM_SIZE 4096
#define SHM_NAME "/myshm"
#define SEM_NAME "/mysem"

typedef struct {
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    char buffer[SHM_SIZE];
} shm_t;

int main(int argc, char *argv[]) {
    int fd, pid;
    shm_t *shm;
    pthread_mutexattr_t mutex_attr;
    pthread_condattr_t cond_attr;

    // 創(chuàng)建共享內(nèi)存區(qū)域
    fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
    if (fd < 0) {
        perror("shm_open");
        exit(1);
    }

    // 設置共享內(nèi)存大小
    if (ftruncate(fd, sizeof(shm_t)) < 0) {
        perror("ftruncate");
        exit(1);
    }

    // 將共享內(nèi)存映射到進程地址空間
    shm = mmap(NULL, sizeof(shm_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (shm == MAP_FAILED) {
        perror("mmap");
        exit(1);
    }

    // 初始化互斥量屬性和條件變量屬性
    pthread_mutexattr_init(&mutex_attr);
    pthread_condattr_init(&cond_attr);
    pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
    pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);

    // 初始化互斥量和條件變量
    pthread_mutex_init(&shm->mutex, &mutex_attr);
    pthread_cond_init(&shm->cond, &cond_attr);

    // 創(chuàng)建子進程
    pid = fork();
    if (pid < 0) {
        perror("fork");
        exit(1);
    }

    if (pid == 0) {
        // 子進程寫入共享內(nèi)存
        sleep(1);
        pthread_mutex_lock(&shm->mutex);
        sprintf(shm->buffer, "Hello, world!");
        pthread_cond_signal(&shm->cond);
        pthread_mutex_unlock(&shm->mutex);
        exit(0);
    } else {
        // 父進程讀取共享內(nèi)存
        pthread_mutex_lock(&shm->mutex);
        pthread_cond_wait(&shm->cond, &shm->mutex);
        printf("Received message: %s\\n", shm->buffer);
        pthread_mutex_unlock(&shm->mutex);
    }

    // 刪除共享內(nèi)存
    if (shm_unlink(SHM_NAME) < 0) {
        perror("shm_unlink");
        exit(1);
    }

    return 0;
}

在這個示例中,程序創(chuàng)建了一個名為"/myshm"的共享內(nèi)存區(qū)域,并將其映射到進程地址空間中。 然后,程序使用互斥量和條件變量來同步進程之間的訪問共享內(nèi)存區(qū)域。 具體來說,父進程首先鎖定互斥量,然后等待條件變量的信號。 子進程等待一秒鐘后,鎖定互斥量,將"Hello, world!"字符串寫入共享內(nèi)存區(qū)域,然后發(fā)送條件變量信號,并釋放互斥量。 此時,父進程將收到條件變量信號并鎖定互斥量,讀取共享內(nèi)存區(qū)域中的內(nèi)容,并釋放互斥量。

需要注意的是,在使用條件變量時,我們需要遵循一些規(guī)則來保證程序的正確性,如在等待條件變量時必須鎖定互斥量,并使用while循環(huán)來檢查條件變量的值是否滿足要求,等待條件變量信號的線程必須在等待之前鎖定互斥量,在等待之后解鎖互斥量,等待條件變量信號的線程可能會因為接收到信號而提前返回等等。

總之,使用互斥量和條件變量來實現(xiàn)進程間共享內(nèi)存通信的同步,需要我們仔細考慮程序中所有可能出現(xiàn)的情況,并正確地使用互斥量和條件變量函數(shù)來同步進程之間的訪問。

小結(jié)

好了,這次我們通過Linux下進程間共享內(nèi)存通信方式講解了常用的同步機制:信號量、互斥鎖、條件變量。 希望對小伙伴們在日常的編程當中有所幫助。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 通信
    +關(guān)注

    關(guān)注

    18

    文章

    6203

    瀏覽量

    137729
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11508

    瀏覽量

    213558
  • 共享內(nèi)存
    +關(guān)注

    關(guān)注

    0

    文章

    16

    瀏覽量

    8419
  • 進程
    +關(guān)注

    關(guān)注

    0

    文章

    207

    瀏覽量

    14271
  • 信號量
    +關(guān)注

    關(guān)注

    0

    文章

    53

    瀏覽量

    8557
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    Linux進程如何實現(xiàn)共享內(nèi)存通信

    這次我們來講一下Linux進程通信中重要的通信方式:共享內(nèi)存作為
    發(fā)表于 04-26 17:14 ?811次閱讀

    Linux進程共享內(nèi)存通信常用的同步機制

    今天我們來講講進程間使用共享內(nèi)存通信時為了確保數(shù)據(jù)的正確,如何進行同步?
    發(fā)表于 06-20 09:41 ?1469次閱讀

    linux操作系統(tǒng)下的進程通信設計

    不需要在不同的進程復制。通常由一個進程創(chuàng)建一塊共享內(nèi)存區(qū),其余進程對這塊
    發(fā)表于 04-16 09:17

    Linux進程通信方式-管道

    Linux進程通信方式-管道分享到: 本文關(guān)鍵字: linux 管道通信
    發(fā)表于 08-29 15:29

    Linux進程通信——使用共享內(nèi)存

    Linux進程通信——使用共享內(nèi)存 圖文詳情見附件
    發(fā)表于 11-21 10:53

    Linux現(xiàn)有的所有進程IPC方式

    ;不合適頻繁或信息量大的通信;3. 共享內(nèi)存:無須復制,共享緩沖區(qū)直接付附加到進程虛擬地址空間,速度快;但
    發(fā)表于 08-20 06:17

    進程通信共享內(nèi)存

    8.5.1 共享內(nèi)存概述 可以說,共享內(nèi)存是一種最為高效的進程
    發(fā)表于 10-18 16:08 ?1次下載
    <b class='flag-5'>進程</b><b class='flag-5'>間</b><b class='flag-5'>通信</b>之<b class='flag-5'>共享</b><b class='flag-5'>內(nèi)存</b>

    linux進程通信方式

    共享內(nèi)存 是被多個進程共享的一部分物理內(nèi)存。共享內(nèi)存
    發(fā)表于 03-06 10:11 ?610次閱讀

    你知道Linux共享內(nèi)存與tmpfs文件系統(tǒng)是什么樣?

    共享內(nèi)存主要用于進程通信,Linux有兩種共享
    發(fā)表于 05-04 17:33 ?2257次閱讀
    你知道<b class='flag-5'>Linux</b>的<b class='flag-5'>共享</b><b class='flag-5'>內(nèi)存</b>與tmpfs文件系統(tǒng)是什么樣?

    Linux進程通信

    linux使用的進程通信方式:(1)管道(pipe)和有名管道(FIFO)(2)信號(signal)(3)消息隊列(4)共享
    發(fā)表于 04-02 14:46 ?581次閱讀

    ipcs命令:用于查看Linux進程通信設施的狀態(tài)

    ? 1.命令簡介 ipcs 命令用于查看 Linux 進程通信設施的狀態(tài),包括消息列表、共享內(nèi)存
    的頭像 發(fā)表于 02-02 11:10 ?2815次閱讀

    深入剖析Linux共享內(nèi)存原理

    不同進程之間進行通信,需要讓不同進程共享相同的物理內(nèi)存Linux通過?
    的頭像 發(fā)表于 10-30 09:52 ?2526次閱讀
    深入剖析<b class='flag-5'>Linux</b><b class='flag-5'>共享</b><b class='flag-5'>內(nèi)存</b>原理

    Linux系統(tǒng)的共享內(nèi)存的使用

    但有時候為了讓不同進程之間進行通信,需要讓不同進程共享相同的物理內(nèi)存,Linux通過
    的頭像 發(fā)表于 11-14 11:55 ?1579次閱讀

    Linux進程如何實現(xiàn)共享內(nèi)存通信

    在上面的例程中,我們首先使用ftok()函數(shù)生成一個key值作為共享內(nèi)存的標識符。然后使用shmget()函數(shù)創(chuàng)建共享內(nèi)存區(qū)域,shmaddr指向
    發(fā)表于 06-19 09:55 ?790次閱讀

    如何實現(xiàn)一套linux進程通信的機制

    我們知道linux進程通信的組件有管道,消息隊列,socket, 信號量,共享內(nèi)存等。但是
    的頭像 發(fā)表于 11-10 14:56 ?871次閱讀
    如何實現(xiàn)一套<b class='flag-5'>linux</b><b class='flag-5'>進程</b><b class='flag-5'>間</b><b class='flag-5'>通信</b>的機制