2012年1月18日 星期三

Share memory / Semaphore 之一

【轉貼】汐っ阳的嵌入式博客
/*
 * 共享内存
 * 信号量控制共享内存的同步,实现父子进程通信,
 * 思路:
    第一步,创建信号量,映像共享内存
    第二步,创建子进程,让子进程继承父进程所有上下文
    第三步,父进程睡眠一秒,让子进程获得CPU时间
    第四步,子进程运行,立刻进行P操作
    第五步,子进程睡眠4秒,主动放弃CPU
    第六步,父进程获得CPU,但信号量已为0,无法进行P操作,只能继续打酱油,父进程被阻塞
    第七步,子进程接着运行,最后释放共享内存,进行V操作,
    第八步,父进程被换醒,获得信号锁,运行,最后,删除共享内存,退出程序    
 * Lzy 2011-6-16
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/sem.h>

#define SHM_SIZE 1024    //共享内存的大小

int main(void)
{
    int ret,     //临时变量
        pid,     //进程id
        sme_id,  //保存信号量描述符
        shm_id;  //保存共享内存描述符

    key_t sme_key,  //保存信号量键值
          shm_key;  //保存共享内存键值

    char *shmp;        //指向共享内存的首地址
    struct shmid_ds dsbuf;    //定义共享内存信息结构变量

    struct sembuf lock = {0, -1, SEM_UNDO};        //信号量上锁操作的数组指针
    struct sembuf unlock = {0, 1, SEM_UNDO | IPC_NOWAIT};//信号量解锁操作的数组指针

    sme_key = ftok("/dev/shm/t2", 2);   //获取信号量键值
    if(sme_key < 0)
    {
        perror("ftok");
        exit(0);
    }
    sme_id = semget(sme_key, 1, IPC_CREAT | 0666);    //获取信号量ID
    if(sme_id < 0)
    {
        perror("semget");
        exit(0);
    }
    shm_key = ftok("/dev/shm/t2", 1); //获取共享内存键值,路徑要事先建好
    if(shm_key < 0)
    {
        perror("ftok");
        exit(0);
    }
    shm_id = shmget(shm_key, SHM_SIZE, IPC_CREAT | 0666);        //获取共享内存ID
    if(shm_id < 0)
    {
        perror("shmget");
        exit(0);
    }
    shmp = shmat(shm_id, NULL, 0);  //映像共享内存
    if((int)shmp == -1)
    {
        perror("shmat");
        exit(0);
    }
    pid = fork();  //创建子进程
    if(pid < 0)
    {
        perror("fork");
        exit(0);
    }
    else if(pid == 0)  //子进程
    {
        ret = semctl(sme_id, 0, SETVAL, 1);  //初始化信号量,初值设为1 (不懂其意
        if(ret == -1)
        {
            perror("semctl");
            exit(0);
        }
        ret = semop(sme_id, &lock, 1);      //申请访问共享资源,锁定临界资源
        if(ret == -1)
        {
            perror("semop lock--c");
            exit(0);
        }
        sleep(4);     //让子进程睡眠4秒
        strcpy(shmp, "hello\n");    //往共享内存写入数据
        if(shmdt((void *)shmp) < 0)    //使共享内存脱离进程地址空间
        {
            perror("shmdt");
        }
        ret = semop(sme_id, &unlock, 1);        //解锁临界资源
        if(ret == -1)
        {
            perror("semop unlock--c2");
            exit(0);
        }
    }
    else                //父进程
        sleep(1);        //先让子进程运行
        ret = semop(sme_id, &lock, 1);        //申请访问共享资源,锁定临界资源
        if(ret == -1)
        {
            perror("semop lock");
            exit(0);
        }
        if(shmctl(shm_id, IPC_STAT, &dsbuf) < 0)    //获取共享内存信息
        {
            perror("shmctl");
            exit(0);
        }
        else            /* 共享内存的状态信息获取成功 */
        {
             printf("Shared Memory Information:\n");
             printf("\tCreator PID: %d\n", dsbuf.shm_cpid);       /* 输出创建共享内存进程的标识符 */
             printf("\tSize(bytes): %d\n",dsbuf.shm_segsz);       /* 输出共享内存的大小 */
             printf("\tLast Operator PID: %d\n",dsbuf.shm_lpid);  /* 输出上一次操作共享内存进程的标识符 */
             printf("Received message : %s\n", (char *)shmp);     /* 从共享内存中读取数据 */
        }
        if(shmdt((void *)shmp) < 0)    //使共享内存脱离进程地址空间
        {
            perror("shmdt");
            exit(0);
        }
        ret = semop(sme_id, &unlock, 1);        //解锁临界资源
        if(ret == -1)
        {
            perror("semop unlock--p");
            exit(0);
        }
        if(shmctl(shm_id, IPC_RMID, NULL) < 0)    /* 删除前面创建的共享内存 */
        {
            perror("shmctl");
            exit(0);
        }
        ret = semctl(sme_id, 0, IPC_RMID, NULL);    //删除信号量
        if(ret == -1)
        {
            perror("semctl");
            exit(0);
        }
    }
    return 0;
}

ref : 汐っ阳的嵌入式博客

沒有留言:

張貼留言