System V 与 POSIX

System V 与 POSIX

2016年02月20日 16:10:24 时行居正 阅读数:3606

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/firstlai/article/details/50705042

       System V 以及POSIX 对信号量、共享内存、消息队列等进程之间共享方式提供了自己的解决方案。因此,在学习时难免存在疑惑,到底有什么区别,哪种方式更佳。经过网上搜索各种博客,做出简单的总结。

历史

       UNIX两大贡献者贝尔实验室和BSD,在进程之间通信侧重不同,前者基于内核对进程之间的通信手段进行了改进,形成了“System V IPC”,而后者则是基于网络形成了套接字。

       而POSIX则是IEEE制定的标准,目的是为运行在不同操作系统上的软件提供统一的接口,实现者则是不同的操作系统内核开发人员

效率

       在信号量这种常用的同步互斥手段方面,POSIX在无竞争条件下是不会陷入内核的,而SYSTEM V则是无论何时都要陷入内核,因此性能稍差。

冗余

       POSIX的sem_wait函数成功获取信号量后,进程如果意外终止,将无法释放信号量,而System V则提供了SEM_UNDO选项来解决这个问题。因此,相比而言,后者更加可靠。

应用

       可能有小部分操作系统没有实现POSIX标准,System V更加广泛些,但是考虑到可移植性POSIX必然是一个趋势。在IPC,进程间的消息传递和同步上,似乎POSIX用得较普遍,而在共享内存方面,POSIX实现尚未完善,system V仍为主流。

多线程与多进程

       在观察使用进程间通信手段后,会发现在多线程中使用的基本是POSIX标准提供的接口函数,而多进程则是基于System V。但是两者难道就不能交叉使用吗?

       多线程使用System V接口---不建议。线程相对于进程是轻量级的,例如调度的策略开销,如果使用System V这种每次调用都会陷入内核的接口,会丧失线程的轻量优势。所以,多线程之间的通信不使用System V的接口函数。

 

       多进程使用POSIX也是允许的

     以mutex为例 ,POSIX的mutex如果要用于多进程,需要实现如下两点要求:(对于SEM信号量相对简单,因为提供了有名SEM的能够用于多进程,它是内核持续的,详见http://blog.csdn.net/firstlai/article/details/50706243)

 

  • mutex能为多个进程所见;
  • mutex本身不额外使用进程本地的内存,如堆内存。

 

       对于第一条是很好满足的,只需要使mutex驻留在共享内存中,创建子进程之前初始化mutex即可;对于第二条GCC的pthread实现也满足,但是需要通过设置mutex的属性,mutex默认是PTHREAD_PROCESS_PRIVATE,即仅支持单进程。如果mutex驻留于共享内存,但pshared为PTHREAD_PROCESS_PRIVATE,此时多进程操作该mutex的行为是未定义的。因此需要设置为 PTHREAD_PROCESS_SHARED即可。

 

 
  1. #include <pthread.h>

  2. #include <sys/mman.h>

  3. #include <sys/types.h>

  4. pthread_mutex_t *mtx = NULL;

  5. int main() {

  6. //~ reside mutex in shm

  7. mtx = (pthread_mutex_t*)mmap(NULL, sizeof(pthread_mutex_t), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);

  8. if (mtx == MAP_FAILED) {

  9. perror("mmap");

  10. exit(1);

  11. }

  12. pthread_mutexattr_t attr;

  13. pthread_mutexattr_init(&attr); //~necessary, or weird EINVAL error occurs when operating on the mutex

  14. pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);

  15. pthread_mutex_init(mtx, &attr);

  16. //~ here the fork

  17. pid_t pid = fork();

  18. if (pid < 0) {

  19. perror("fork");

  20. exit(1);

  21. } else if (pid > 0) {

  22. //~ parent

  23. //~ lock lock lock

  24. } else {

  25. //~ child

  26. //~ lock lock lock

  27. }

  28. return 0;

  29. }

 

 

 

参考文献

 

http://blog.chinaunix.net/uid-26651253-id-3342091.html

http://blog.csdn.net/xuemiao1234/article/details/6869182

https://www.zhihu.com/question/35169528

http://blog.csdn.net/liangxiaozhang/article/details/8504076

=====================================================================================

=====================================================================================

====================================================================================

System V
key_t ftok(const char *path, int id) // 创建key
int shmget(key_t key, size_t size, int shmflg) // 创建or获取共享内存
void *shmat(int shmid, const void *shmaddr, int shmflg) // 映射共享内存
int shmdt(const void *shmaddr) // 删除共享内存引用
int shmctl(int shmid, int cmd, struct shmid_ds *buf) // 控制共享内存(获取状态,修改属性,删除)


POSIX API
int shm_open(const char *name, int oflag, ...)//创建共享内存段或连接到现有的已命名内存段
int shm_unlink(const char *name)//根据(shm_open()返回的)文件描述符,删除共享内存段
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)//把共享内存段映射到进程的内存
int munmap(void *addr, size_t len)//与mmap操作相反,取消共享内存映射
int msync(void *addr, size_t len, int flags)//用来让共享内存段与文件系统同步----当把文件映射到内存时,这种技术有用

 

===================================================================================

=====================================================================================

======================================================================================

 

进程间通信-共享内存

什么是共享内存

作为Unix/Linux进程间通信最高效的方式,莫过于共享同一块内存区域进行读写操作了。共享内存(Shared Memory)相比其它进程间通信能够提供更好的安全性和使用效率,它本质上就是通过映射同一物理内存空间到不同进程从而实现通信的方式。使用共享内存可以快速地在同一主机不同进程间进行数据交换,而且能够对数据进行随机访问,所以它经常作为主机内部进程间通信的首选,但在数据同步及控制上需要借助于信号/信号量/互斥进行访问控制。

共享内存其实是占用进程的虚拟内存空间的,因为它需要将真实物理地址与虚拟内存空间进行映射,所以即使它在物理上是使用同一块地址,在使用这块共享内存的进程本身看来,它仍然是属于自己可访问地址空间上的一块线性区域。

如何使用共享内存

共享内存使用一般有以下几个步骤:创建/获取共享内存->映射共享内存->使用共享内存->释放共享内存->删除引用。下面从一个简单的例子来了解下它的使用过程。

共享内存API

共享内存涉及以下相关API调用(System V API):

System V

 

/*********************************************************************************************************

ftok

shmget

shmat

shmdt

shmcyl

**********************************************************************************************************/

key_t ftok(const char *path, int id) // 创建key
int shmget(key_t key, size_t size, int shmflg) // 创建or获取共享内存
void *shmat(int shmid, const void *shmaddr, int shmflg) // 映射共享内存
int shmdt(const void *shmaddr) // 删除共享内存引用
int shmctl(int shmid, int cmd, struct shmid_ds *buf) // 控制共享内存(获取状态,修改属性,删除)
  • ftok

它可以根据传入路径及id自动生成一个key,你可以在后续的shmget()调用中使用这个key用做共享内存的标识,不同进程间使用同一共享内存必须知道这个key的。当然,你也完全可以自己定义一个key来标识共享内存以避免路径变化时不同进程生成的key发生不一致的坑。

  • shmget

当创建或获取共享内存时,需要调用shmget(),它接受一个共享内存标识符key,�共享内存大小size以及标志位shmflg。标志位用于确定对共享内存的访问权限控制及相关操作,如IPC_CREATEIPC_EXCL标识符都设置时,如果已经存在该key关联的共享内存,errno将直接返回EEXIST

  • shmat

映射共享内存到当前进程的内存地址空间需要调用此函数,它接收shmid(shmget()返回)、shmaddr(虚拟内存空间地址)及shmflg(控制访问权限及相关操作)这三个参数。这里存在一个坑:如果当前进程多次调用shmat(),并不会出现任何错误,得到的结果反而是在当前进程的虚拟内存地址空间出现多个共享内存地址映射,最终可能导致应用程序的地址空间资源耗尽,同时也可能使共享内存的引用最终无法得到正常的释放。

  • shmdt

删除共享内存引用,接收参数为shmat()返回的内存地址。

  • shmctl

用于控制共享内存,接收参数为shmid(shmget()返回), 操作指令cmd及虚拟内存状态buf。操作指令有三种:查看状态IPC_STAT,设置属性IPC_SET和删除IPC_RMID

POSIX API

/*********************************************************************************************************

shm_open

shm_unlink

mmap

munmap

msync

**********************************************************************************************************/

int shm_open(const char *name, int oflag, ...)
int shm_unlink(const char *name)
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
int munmap(void *addr, size_t len)
int msync(void *addr, size_t len, int flags)
  • shm_open

创建共享内存段或连接到现有的已命名内存段,这个系统调用返回一个文件描述符,name为这段共享内存的命名,oflag为权限控制。

  • shm_unlink

根据(shm_open()返回的)文件描述符,删除共享内存段。实际上,这个内存段直到访问它的所有进程都退出时才会删除,这与在UNIX中删除文件很相似。但是,调用shm_unlink()(通常由原来创建共享内存段的进程调用)之后,其他进程就无法访问这个内存段了。

  • mmap

把共享内存段映射到进程的内存。这个系统调用需要shm_open()返回的文件描述符,它返回指向内存的指针。(在某些情况下,还可以把一般文件或另一个设备的文件描述符映射到内存。)

  • munmap

mmap()操作相反,取消共享内存映射。

  • msync

用来让共享内存段与文件系统同步 — 当把文件映射到内存时,这种技术有用。

共享内存使用

这里用一个简单的例子来解释下共享内存的使用,我们将引入信号来进行同步控制,创建两个进程分别用于负责读和写的操作。

这里先定义一个数据结构

shared_data.h

#ifndef _SHARED_DATA_H_
#define _SHARED_DATA_H_

#include <stdlib.h>

#define BUFFER_SIZE 1024

typedef struct {
    pid_t pid;
    char buffer[BUFFER_SIZE];
} shared_data;

#endif

pid用于记录等待信号的对象进程,buffer用于记录数据。

基于System V API

读程序

shmread.c

#include "shmutils.h"

void handler(int signo)
{
    printf("READER: get signal\n");
}

int main(int argc, char** argv)
{
    bool running = true;
    pid_t pid;
    key_t shm_key;
    if ((shm_key = ftok(".", 'm')) < 0)
    {
        perror("READER: call ftok failed!");
        exit(EXIT_FAILURE);
    }

    printf("READER: shm_key: %d\n", shm_key);
    signal(SIGUSR1, handler);
    void* shm_p = NULL;
    shared_data* shm_data = NULL;
    int shm_id = shmget(shm_key, sizeof(shared_data), 0666 | IPC_CREAT | IPC_EXCL);
    if (shm_id == -1)
    {
        if (EEXIST == errno)
        {
        
    printf("READER: share memory for key[%d] exist!\n", shm_key);
            shm_id = shmget(shm_key, sizeof(shared_data), 0666);

            shm_data = (shared_data*)shmat(shm_id, NULL, 0);
            pid = shm_data->pid;
            shm_data->pid = getpid();
            kill(pid, SIGUSR1);
        }
        else
        {
            perror("READER: call shmget failed!\n");
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        shm_p = shmat(shm_id, NULL, 0);
        shm_data = (shared_data*)shm_p;
        shm_data->pid = getpid();
        pause(); // wait for awake
        pid = shm_data->pid;
    }

    while (running)
    {
        pause();
        if (strcmp(shm_data->buffer, END_STR) == 0)
        {
            running = false;
        }
        printf("READER: read from shm: %s\n", shm_data->buffer);
        kill(pid, SIGUSR1);
    }
    shmdt(shm_p);
    shmctl(shm_id, IPC_RMID, NULL);
    return 0;
}

#include "shmutils.h"

void handler(int signo)
{
    printf("READER: get signal\n");
}

int main(int argc, char** argv)
{
    bool running = true;
    pid_t pid;
    key_t shm_key;
    if ((shm_key = ftok(".", 'm')) < 0)
    {
        perror("READER: call ftok failed!");
        exit(EXIT_FAILURE);
    }
    printf("READER: shm_key: %d\n", shm_key);
    signal(SIGUSR1, handler);
    void* shm_p = NULL;
    shared_data* shm_data = NULL;
    int shm_id = shmget(shm_key, sizeof(shared_data), 0666 | IPC_CREAT | IPC_EXCL);
    if (shm_id == -1)
    {
        if (EEXIST == errno)
        {
            printf("READER: share memory for key[%d] exist!\n", shm_key);
            shm_id = shmget(shm_key, sizeof(shared_data), 0666);
            shm_data = (shared_data*)shmat(shm_id, NULL, 0);
            pid = shm_data->pid;
            shm_data->pid = getpid();
            kill(pid, SIGUSR1);
        }
        else
        {
            perror("READER: call shmget failed!\n");
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        shm_p = shmat(shm_id, NULL, 0);
        shm_data = (shared_data*)shm_p;
        shm_data->pid = getpid();
        pause(); // wait for awake
        pid = shm_data->pid;
    }
    while (running)
    {
        pause();
        if (strcmp(shm_data->buffer, END_STR) == 0)
        {
            running = false;
        }
        printf("READER: read from shm: %s\n", shm_data->buffer);
        kill(pid, SIGUSR1);
    }
    shmdt(shm_p);
    shmctl(shm_id, IPC_RMID, NULL);
    return 0;
}

写程序

shmwrite.c

#include "shmutils.h"

void handler(int signo)
{
    printf("WRITER: get signal\n");
}

int main(int argc, char** argv)
{
    bool running = true;
    key_t shm_key;
    if ((shm_key = ftok(".", 'm')) < 0)
    {
        perror("WRITER: call ftok failed!");
        exit(EXIT_FAILURE);
    }

    printf("WRITER: shm_key: %d\n", shm_key);
    signal(SIGUSR1, handler);
    pid_t pid;
    void* shm_p = NULL;
    shared_data* shm_data = NULL;
    int shm_id = shmget(shm_key, sizeof(shared_data), 0666 | IPC_CREAT | IPC_EXCL);
    if (shm_id == -1)
    {
        if (errno == EEXIST)
        {
            printf("WRITER: share memory for key[%d] exist!\n", shm_key);
            shm_id = shmget(shm_key, sizeof(shared_data), 0666);
          
  shm_data = (shared_data*)shmat(shm_id, NULL, 0);
            pid = shm_data->pid;
            shm_data->pid = getpid();
            kill(pid, SIGUSR1);

        }
        else
        {
            perror("WRITER: call shmget failed!\n");
            exit(EXIT_FAILURE);
        }
    }

    else
    {
        shm_p = shmat(shm_id, NULL, 0);
        shm_data = (shared_data*)shm_p;
        shm_data->pid = getpid();
        pause();
        pid = shm_data->pid;
    }
    while (running)
    {
        printf("WRITER: write to shm: ");
        fgets(shm_data->buffer, BUFFER_SIZE, stdin);
        kill(pid, SIGUSR1);
        if (strcmp(shm_data->buffer, END_STR) == 0)
        {
            running = false;
            break;
        }
        pause();
    }
    shmdt(shm_p);
    shmctl(shm_id, IPC_RMID, NULL);
    return 0;
}

#include "shmutils.h"

void handler(int signo)
{
    printf("WRITER: get signal\n");
}

int main(int argc, char** argv)
{
    bool running = true;
    key_t shm_key;
    if ((shm_key = ftok(".", 'm')) < 0)
    {
        perror("WRITER: call ftok failed!");
        exit(EXIT_FAILURE);
    }
    printf("WRITER: shm_key: %d\n", shm_key);
    signal(SIGUSR1, handler);
    pid_t pid;
    void* shm_p = NULL;
    shared_data* shm_data = NULL;
    int shm_id = shmget(shm_key, sizeof(shared_data), 0666 | IPC_CREAT | IPC_EXCL);
    if (shm_id == -1)
    {
        if (errno == EEXIST)
        {
            printf("WRITER: share memory for key[%d] exist!\n", shm_key);
            shm_id = shmget(shm_key, sizeof(shared_data), 0666);
            shm_data = (shared_data*)shmat(shm_id, NULL, 0);
            pid = shm_data->pid;
            shm_data->pid = getpid();
            kill(pid, SIGUSR1);
        } 
        else
        {
            perror("WRITER: call shmget failed!\n");
            exit(EXIT_FAILURE);
        }
    }
    else 
    {
        shm_p = shmat(shm_id, NULL, 0);
        shm_data = (shared_data*)shm_p;
        shm_data->pid = getpid();
        pause();
        pid = shm_data->pid;
    }
    while (running)
    {
        printf("WRITER: write to shm: ");
        fgets(shm_data->buffer, BUFFER_SIZE, stdin);
        kill(pid, SIGUSR1);
        if (strcmp(shm_data->buffer, END_STR) == 0)
        {
            running = false;
            break;
        }
        pause();
    }
    shmdt(shm_p);
    shmctl(shm_id, IPC_RMID, NULL);
    return 0;
}

执行结果

▶ ./shmread &
[1] 78735
READER: shm_key: 1829132911 
▶ ./shmwrite 
WRITER: shm_key: 1829132911
WRITER: share memory for key[1829132911] exist!
READER: get signal
WRITER: write to shm: Hello, reader!
READER: get signal
READER: read from shm: Hello, reader!

WRITER: get signal
WRITER: write to shm: Do you know who I am?
READER: get signal
READER: read from shm: Do you know who I am?

WRITER: get signal
WRITER: write to shm: end
READER: get signal
READER: read from shm: end

[1]  + 78735 done       ./shmread

基于POSIX API

读程序

shmread.c

#include "shmutils.h"

void handler(int signo)
{
    printf("READER: get signal\n");
}

int main(int argc, char** argv)
{
    bool running = true;
    pid_t pid;
    signal(SIGUSR1, handler);
    void* shm_p = NULL;
    shared_data* shm_data = NULL;
    int shm_id = shm_open(IPC_SHM_NAME, O_CREAT | O_RDWR | O_EXCL, 0666);
    if (shm_id == -1)
    {
        if (EEXIST == errno)
        {
            printf("READER: share memory for key[%s] exist!\n", IPC_SHM_NAME);
            shm_id = shm_open(IPC_SHM_NAME, O_RDWR, 0666);
            ftruncate(shm_id, sizeof(shared_data));
            shm_data = (shared_data*)mmap(0, sizeof(shared_data), PROT_READ | PROT_WRITE, MAP_SHARED, shm_id, 0);
            pid = shm_data->pid;
            shm_data->pid = getpid();
            kill(pid, SIGUSR1);
        }
        else
        {
            perror("READER: call shm_open failed!\n");
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        ftruncate(shm_id, sizeof(shared_data));
        shm_data = (shared_data*)mmap(0, sizeof(shared_data), PROT_READ | PROT_WRITE, MAP_SHARED, shm_id, 0);
        shm_data->pid = getpid();

    }
    while (running)
    {
        printf("READER: wait for awake...\n");
        pause();
        pid = shm_data->pid;
        shm_data->pid = getpid();
        printf("READER: awake from %0x.\n", pid);
        if (strcmp(shm_data->buffer, END_STR) == 0)
        {
            running = false;
        }
        printf("READER: read from shm: %s\n", shm_data->buffer);
        sleep(1);
        kill(pid, SIGUSR1);
    }
    munmap(shm_p, sizeof(shared_data));
    shm_unlink(IPC_SHM_NAME);
    return 0;
}

#include "shmutils.h"

void handler(int signo)
{
    printf("READER: get signal\n");
}

int main(int argc, char** argv)
{
    bool running = true;
    pid_t pid;
    signal(SIGUSR1, handler);
    void* shm_p = NULL;
    shared_data* shm_data = NULL;
    int shm_id = shm_open(IPC_SHM_NAME, O_CREAT | O_RDWR | O_EXCL, 0666);
    if (shm_id == -1)
    {
        if (EEXIST == errno)
        {
            printf("READER: share memory for key[%s] exist!\n", IPC_SHM_NAME);
            shm_id = shm_open(IPC_SHM_NAME, O_RDWR, 0666);
            ftruncate(shm_id, sizeof(shared_data));
            shm_data = (shared_data*)mmap(0, sizeof(shared_data), PROT_READ | PROT_WRITE, MAP_SHARED, shm_id, 0);
            pid = shm_data->pid;
            shm_data->pid = getpid();
            kill(pid, SIGUSR1);
        }
        else
        {
            perror("READER: call shm_open failed!\n");
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        ftruncate(shm_id, sizeof(shared_data));
        shm_data = (shared_data*)mmap(0, sizeof(shared_data), PROT_READ | PROT_WRITE, MAP_SHARED, shm_id, 0);
        shm_data->pid = getpid();
    }
    while (running)
    {
        printf("READER: wait for awake...\n");
        pause();
        pid = shm_data->pid;
        shm_data->pid = getpid();
        printf("READER: awake from %0x.\n", pid);
        if (strcmp(shm_data->buffer, END_STR) == 0)
        {
            running = false;
        }
        printf("READER: read from shm: %s\n", shm_data->buffer);
        sleep(1);
        kill(pid, SIGUSR1);
    }
    munmap(shm_p, sizeof(shared_data));
    shm_unlink(IPC_SHM_NAME);
    return 0;
}

写程序

shmwrite.c

#include "shmutils.h"

void handler(int signo)
{
    printf("WRITER: get signal\n");
}

int main(int argc, char** argv)
{
    bool running = true;
    signal(SIGUSR1, handler);
    pid_t pid;
    void* shm_p = NULL;
    shared_data* shm_data = NULL;
    int shm_id = shm_open(IPC_SHM_NAME, O_CREAT | O_RDWR | O_EXCL, 0666);
    if (shm_id == -1)
    {
        if (errno == EEXIST)
        {
            printf("WRITER: share memory for key[%s] exist!\n", IPC_SHM_NAME);
            shm_id = shm_open(IPC_SHM_NAME, O_RDWR, 0666);
            ftruncate(shm_id, sizeof(shared_data));
            shm_data = (shared_data*)mmap(0, sizeof(shared_data), PROT_WRITE, MAP_SHARED, shm_id, 0);

            pid = shm_data->pid;
            shm_data->pid = getpid();
        }
        else
        {
            perror("WRITER: call shm_open failed!\n");
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        ftruncate(shm_id, sizeof(shared_data));
        shm_data = (shared_data*)mmap(0, sizeof(shared_data), PROT_READ, MAP_SHARED, shm_id, 0);
        shm_data->pid = getpid();

    }
    while (running)
    {
        printf("WRITER: write to shm: ");
        fflush(stdout);
        fgets(shm_data->buffer, BUFFER_SIZE, stdin);
        sleep(1);
        kill(pid, SIGUSR1);
        if (strcmp(shm_data->buffer, END_STR) == 0)
        {
            running = false;
            break;
        }
        printf("WRITER: wait for awake...\n");
        pause();
        pid = shm_data->pid;
        shm_data->pid = getpid();
        printf("WRITER: awake from %0x.\n", pid);
    }
    munmap(shm_p, sizeof(shared_data));
    shm_unlink(IPC_SHM_NAME);
    return 0;
}

#include "shmutils.h"

void handler(int signo)
{
    printf("WRITER: get signal\n");
}

int main(int argc, char** argv)
{
    bool running = true;
    signal(SIGUSR1, handler);
    pid_t pid;
    void* shm_p = NULL;
    shared_data* shm_data = NULL;
    int shm_id = shm_open(IPC_SHM_NAME, O_CREAT | O_RDWR | O_EXCL, 0666);
    if (shm_id == -1)
    {
        if (errno == EEXIST)
        {
            printf("WRITER: share memory for key[%s] exist!\n", IPC_SHM_NAME);
            shm_id = shm_open(IPC_SHM_NAME, O_RDWR, 0666);
            ftruncate(shm_id, sizeof(shared_data));
            shm_data = (shared_data*)mmap(0, sizeof(shared_data), PROT_WRITE, MAP_SHARED, shm_id, 0);
            pid = shm_data->pid;
            shm_data->pid = getpid();
        } 
        else
        {
            perror("WRITER: call shm_open failed!\n");
            exit(EXIT_FAILURE);
        }
    }
    else 
    {
        ftruncate(shm_id, sizeof(shared_data));
        shm_data = (shared_data*)mmap(0, sizeof(shared_data), PROT_READ, MAP_SHARED, shm_id, 0);
        shm_data->pid = getpid();
    }
    while (running)
    {
        printf("WRITER: write to shm: ");
        fflush(stdout);
        fgets(shm_data->buffer, BUFFER_SIZE, stdin);
        sleep(1);
        kill(pid, SIGUSR1);
        if (strcmp(shm_data->buffer, END_STR) == 0)
        {
            running = false;
            break;
        }
        printf("WRITER: wait for awake...\n");
        pause();
        pid = shm_data->pid;
        shm_data->pid = getpid();
        printf("WRITER: awake from %0x.\n", pid);
    }
    munmap(shm_p, sizeof(shared_data));
    shm_unlink(IPC_SHM_NAME);
    return 0;
}

运行结果在这里就不再描述了。

共享内存进阶

System V API

查看共享内存

查看共享内存可以使用ipcs -m即可,比如我们运行./shread时,查看共享内存看到的信息:

▶ ipcs -m
IPC status from <running system> as of Sun Aug  6 14:41:33 CST 2017
T     ID     KEY        MODE       OWNER    GROUP
Shared Memory:
m 851968 0x6d065a6f --rw-rw-rw-  wangqun    staff

删除共享内存

删除共享内存可以使用ipcrm -m $ID来操作,比如我们想删除我们查询到的�ID851968的共享内存,直接使用ipcrm -m 851968即可。

配置共享内存参数

在Linux主机上,共享内存大小及数量都是可以通过内核参数进行控制的,这些参数都在/proc/sys/kernel下。

  • SHMMAX: 设置共享内存的最大值
  • SHMMNI: 设置共享内存的最大使用数量
  • SHMALL: 设置系统一次可用的共享内存总量,该值至少为ceil(SHMMAX/PAGE_SIZE)

POSIX API

使用POSIX API进行共享内存申请时,不受内参数限制,只受物理内存限制,所以相比System V API少了使用上的限制,但如果想要查询共享内存的信息就不如System V API方便了。

使用文件进行mmap

在使用mmap()时,其实我们是可以使用文件fd来进行mmap的,这样我们的共享内存数据是可以同步到文件中实现持久化的目的。

全部测试代码可以在我的GitHub上找到。

原文链接:https://wangqun.info/2017/08/06/%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1-%E5%85%B1%E4%BA%AB%E5%86%85%E5%AD%98/

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值