多进程共享内存与信号量进程同步方式

shdata.h

#include <mutex>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
#include <cassert>

using std::mutex;

struct Person {
    char name[256];
    int age;
    Person(const char* name, int age);
};

#define IPCKEY 0x111

Person::Person(const char* name, int age)
{
    strcpy(this->name, name);
    this->age = age;
}

typedef Person DataType;

class Shmman {
private:
    DataType* map_ptr_;
    key_t ipc_key_;
    size_t buf_size_;
    int shm_id_;
    mutex mtx_inner_;
    bool init(size_t buf_size, int mod_flags);
    Shmman(const Shmman& chs);

public:
    bool write(DataType* dataptr);
    void read();

    Shmman(key_t ipc_key, size_t buf_size, int mod_flags);
    ~Shmman();
};

Shmman::~Shmman()
{
    shmctl(shm_id_, IPC_RMID, 0);
}

Shmman::Shmman(key_t ipc_key, size_t buf_size, int mod_flags)
{
    ipc_key_ = ipc_key;
    shm_id_ = -1;
    buf_size_ = buf_size;
    map_ptr_ = NULL;
    init(buf_size, mod_flags);
}

bool Shmman::init(size_t buf_size, int mod_flags)
{
    if (ipc_key_ == -1) {
        printf("init failed: invalid ipc_key_(-1)!\n");
        return false;
    }
    shm_id_ = shmget(ipc_key_, buf_size, mod_flags);
    assert(shm_id_ != -1);
    if (shm_id_ == -1) {
        printf("shmget failed: shm_id_(-1)\n");
        return false;
    }
    map_ptr_ = (DataType*)shmat(shm_id_, 0, 0);
    assert(map_ptr_ != NULL);
    return true;
}

bool Shmman::write(DataType* dataptr)
{
    if (dataptr == NULL) {
        printf("Shmman::write failed: dataptr is NULL\n");
        return false;
    }
    if (map_ptr_ == NULL) {
        printf("Shmman::write failed: map_ptr_ is NULL!\n");
        return false;
    }
#ifdef INNERLOCK
    mtx_inner_.lock();
#endif
    strcpy(map_ptr_->name, dataptr->name);
    map_ptr_->age = dataptr->age;
#ifdef INNERLOCK
    mtx_inner_.unlock();
#endif

    return true;
}

void Shmman::read()
{
    if (map_ptr_ == NULL) {
        printf("Shmman::read failed: map_ptr_ is NULL\n");
        return;
    }
#ifdef INNERLOCK
    mtx_inner_.lock();
#endif
    printf("%s pid:%d\n", map_ptr_->name, map_ptr_->age);
#ifdef INNERLOCK
    mtx_inner_.unlock();
#endif
}

executor.cc

#include <unistd.h>
#include <sys/wait.h>
#include <sys/sem.h>
#include "shdata.h"

union semun
{
    int val;
    struct semid_ds* buf;
    unsigned short int* array;
    struct seminfo* __buf;
};

void pv(int semid, int op)
{
    struct sembuf sem_buf;
    sem_buf.sem_num = 0;
    sem_buf.sem_op = op;
    sem_buf.sem_flg = SEM_UNDO;
    semop(semid, &sem_buf, 1);
}

//#define INNERLOCK

int main(int argc, const char** argv)
{
    key_t ipc_key = ftok("/tmp", IPCKEY);
    if (ipc_key == -1) {
        printf("ftok error\n");
        return -1;
    }
    size_t buf_size = 4096;
    int mod_flags = IPC_CREAT | IPC_EXCL | 0600;
    Shmman* shmman = new Shmman(ipc_key, buf_size, mod_flags);

    int semid = semget(IPC_PRIVATE, 1, 0666);
    union semun sem_un;
    sem_un.val = 1;
    semctl(semid, 0, SETVAL, sem_un);

    pid_t pid;
    int i = 0;
    const int nprocess = 8;
    for ( ; i < nprocess; i++) {
        pid = fork();
        if (pid == 0)    break;
    }

    if (pid < 0) {
        printf("fork failed\n");
        return -1;
    } else if (pid == 0) {
        char msg[256];
        pid_t cur = getpid();
        sprintf(msg, "卧槽尼玛:%d", cur);
        DataType data(msg, cur);
#ifndef INNERLOCK
        pv(semid, 1);
#endif
        shmman->write(&data);
#ifdef INNERLOCK
        pv(semid, -1);
#endif
        return 0;
    } else {
        pid_t pid_chd;
        int cnt = 0;
        printf("wait for child process ternimal\n");
        while (true) {
            pid_chd = waitpid(-1, 0, WNOHANG);
            if (pid_chd > 0)    cnt++;
            if (cnt == nprocess)    break;
#ifndef INNERLOCK
            pv(semid, 1);
#endif
            shmman->read();
#ifndef INNERLOCK
            pv(semid, -1);
#endif
        }

        printf("%d child process ternimated\n", cnt);

        delete shmman;
        semctl(semid, 0, IPC_RMID, sem_un);
        return 0;
    }

}

Makefile 文件:

CC=clang++-3.5

CXXFLAGS=-std=c++11

main : executor.o
	$(CC) executor.o -o main

executor.o : executor.cc shdata.h
	$(CC) -c executor.cc shdata.h $(CXXFLAGS)

rest :
	ipcs | grep 4096 | cut -c 12-18 | xargs ipcrm -m

clean :
	rm main *.o *.gch
时间: 2024-10-09 03:32:03

多进程共享内存与信号量进程同步方式的相关文章

unix/linux下的共享内存、信号量、队列信息管理

在unix/linux下,经常有因为共享内存.信号量,队列等共享信息没有干净地清楚而引起一些问题.查看共享信息的内存的命令是ipcs [-m|-s|-q]. 默认会列出共享内存.信号量,队列信息,-m列出共享内存,-s列出共享信号量,-q列出共享队列清除命令是ipcrm [-m|-s|-q] id.-m 删除共享内存,-s删除共享信号量,-q删除共享队列.

37. Python 多进程锁 多进程共享内存

Lock组件 当我们用多进程来读写文件的时候,如果一个进程是写文件,一个进程是读文件, 如果两个文件同时进行,肯定是不行的,必须是文件写结束后,才可以进行读操作. 或者是多个进程在共享一些资源的时候,同时只能有一个进程进行访问,那就需要锁机制进行控制. 需求: 一个进程写入一个文件,一个进程追加文件,一个进程读文件,同时启动起来 我们可以通过进程的join()方法来实现,这是一种方法,本节用Lock(进程锁)来实现. 函数说明: # lock = multiprocessing.Lock() #

linux使用共享内存通信的进程同步退出问题

两个甚至多个进程使用共享内存(shm)通信,总遇到同步问题.这里的“同步问题”不是说进程读写同步问题,这个用信号量就好了.这里的同步问题说的是同步退出问题,到底谁先退出,怎么知道对方退出了.举个例子:进程负责读写数据库A,进程B负责处理数据.那么进程A得比进程B晚退出才行,因为要保存进程B处理完的数据.可是A不知道B什么时候退出啊.A.B是无关联的进程,也不知道对方的pid.它们唯一的关联就是读写同一块共享内存.正常情况下,进程B在共享内存中写个标识:进程A你可以退出了,也是可以的.不过进程B可

共享内存和信号量

1) 获取信号量标识符 int semget(key_t key, int nsems, int flag)2) 操作信号量(初始化,删除等) int semctl(int semid, int semnum, int cmd, /*union semun*/)3) 对信号量进行增减操作,在该操作是一个原子操作 int semop(int semid, struct sembuf  semoparray[ ], size_t nops) sem.h #include <sys/shm.h> #

python多进程共享内存

from multiprocessing import Process,Manager,Lock import os import time def run_proc(dict,slip,lock): tmp=dict[slip].copy() for k in dict[slip]: tmp[k]=k+tmp[k] print('Run child process{ch}... '.format(ch=os.getpid())) with lock: dict[slip]=tmp if __n

Linux下用信号量实现对共享内存的访问保护

转自:http://www.cppblog.com/zjl-1026-2001/archive/2010/03/03/108768.html 最近一直在研究多进程间通过共享内存来实现通信的事情,以便高效率地实现对同一数据的访问.本文中对共享内存的实现采用了系统V的机制,我们的重点在于通过信号量来完成对不同进程间共享内存资源的一致性访问,共享内存的具体方法请参见相关资料,这里不再赘述. 首先我们先实现最简单的共享内存,一个进程对其更新,另一个进程从中读出数据.同时,通过信号量的PV操作来达到对共享

进程间通信IPC:消息队列,信号量,共享内存

2015.3.4星期三 阴天 进程间通信:IPC 文件对象:记录文件描述符,文件开关等 IPC标示符:系统全局的流水号两个进程要通信,打开的是唯一的对象进行通讯,通过key操作 XSI IPC:消息队列,信号量,共享内存. ipcs 查看ip对象共享内存,信号量,消息队列等信息ipcrm 删除一个IP对象 Linux为用户提供了完善的,强大的网络功能完善的内置网络:其他操作系统不包含如此紧密的和内核结合在一起的网络部分 共享内存标示符的获取有两种方法:ftok(pathname,id)另一个是K

Linux进程间通信 共享内存+信号量+简单例子

每一个进程都有着自己独立的地址空间,比如程序之前申请了一块内存,当调用fork函数之后,父进程和子进程所使用的是不同的内存.因此进程间的通信,不像线程间通信那么简单.但是共享内存编程接口可以让一个进程使用一个公共的内存区段,这样我们便能轻易的实现进程间的通信了(当然对于此内存区段的访问还是要控制好的). 共享内存实现进程通信的优点: 共享内存是进程通信方式中最快速的方式之一,它的快速体现在,为数据共享而进行的复制非常少.这里举例来说,使用消息队列时,一个进程向消息队列写入消息时,这里有一次数据的

Linux进程间通信 共享内存+信号量+简单样例

每个进程都有着自己独立的地址空间,比方程序之前申请了一块内存.当调用fork函数之后.父进程和子进程所使用的是不同的内存. 因此进程间的通信,不像线程间通信那么简单.可是共享内存编程接口能够让一个进程使用一个公共的内存区段,这样我们便能轻易的实现进程间的通信了(当然对于此内存区段的訪问还是要控制好的). 共享内存实现进程通信的长处: 共享内存是进程通信方式中最高速的方式之中的一个,它的高速体如今,为数据共享而进行的复制很少.这里举例来说.使用消息队列时.一个进程向消息队列写入消息时.这里有一次数