Linux系統編程. IPC方式:共享內存和信號量 . 簡單複習

信號量和共享內存簡單實例練習:共享內存是所有IPC中最快的,但是需要某種形式的進程同步策略,通常選用信號量進行同步。

// 文件創建訪問權限
#define RWRWRW (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)

int main(int argc, char *argv[])
{
        int fd = -1;
        char* ptr = nullptr;
        sem_t* sem_ = nullptr;

        char zero_buffer[4096] = { 0 };

        fd = open("test", O_RDWR | O_CREAT, RWRWRW);
        assert(-1 != fd);
        // 這一步注意,要映射多大空間,源文件就需要有多大尺寸,否則mmap的時候空間會小於指定大小
        write(fd, zero_buffer, 4096);

        // 上一步打開文件的操作可以省略,指定flag | MAP_ANON,並且將fd設置爲-1即可, 此時offset參數會被忽略
        // 創建映射文件區
        ptr = (char *)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        assert(nullptr != ptr);

        // 關閉文件描述符
        close(fd);

        // 有名信號量
        sem_ = sem_open("sem_file", O_CREAT | O_EXCL, RWRWRW, 1);
        assert(nullptr != sem_);
        // 刪除與信號量關聯的輔助文件
        sem_unlink("sem_file");

        if (0 == fork()) { // 子進程讀
                while (1) {
                        sem_wait(sem_);
                        printf("child: %s\n", ptr);
                        sem_post(sem_);

                        sleep(1);
                }
                return 0;
        }

        // 父進程寫
        while (1) {
                sem_wait(sem_);

                memset(ptr, 0, 4096);
                strcat(ptr, "this is mmap test.");

                sem_post(sem_);
                sleep(1);
        }
        return 0;
}

基於內存的信號量(無名信號量):

// 文件創建訪問權限
#define RWRWRW (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)

int main()
{
        int fd = -1;
        char* ptr = nullptr;
        sem_t sem_;

        char zero_buffer[4096] = { 0 };

        fd = open("test", O_RDWR | O_CREAT, RWRWRW);
        assert(-1 != fd);
        write(fd, zero_buffer, 4096);

        // 創建映射文件區
        ptr = (char *)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        assert(nullptr != ptr);

        // 關閉文件描述符
        close(fd);

        // 無名信號量
        sem_init(&sem_, 1, 1);
        
        if (0 == fork()) { // 子進程讀
                while (1) {
                        sem_wait(&sem_);
                        printf("child: %s\n", ptr);
                        sem_post(&sem_);

                        sleep(1);
                }
                return 0;
        }

        // 父進程寫
        while (1) {
                sem_wait(&sem_);

                memset(ptr, 0, 4096);
                strcat(ptr, "this is mmap test.");

                sem_post(&sem_);
                sleep(1);
        }
        return 0;
}

這裏還需要注意一點是:

SIGSEGV和SIGBUS的引發錯誤的區別:

SIGBUS意味着任然在內存映射區內訪問,但是超出了底層支撐對象的大小。

SIGSEGV意味着我們已經在映射區以外訪問。

另外:映射區分配是以頁面大小整數倍分配的,如果頁面大小爲4096,那麼mmapsize = 5000時實際分配的映射區大小向上取整爲8096.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章