分享

C++通过信号量控制共享内存的读写

 禁忌石 2017-04-24

C++通过信号量控制共享内存的读写

作者:qiyuefeng11 博客  发布日期:2012-09-06 09:06:35
0
Tag标签:信号量  共享内存  
  • 信号量函数定义如下:

    #include <sys/sem.h>
    int semctl(int sem_id, int sem_num, int command, ...);
    int semget(key_t key, int num_sems, int sem_flags);
    int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);
    semop

    函数semop用来改变信号量的值:

    int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);

    第一个参数,sem_id,是由semget函数所返回的信号量标识符。第二个参数,sem_ops,是一个指向结构数组的指针,其中的每一个结构至少包含下列成员:

    struct sembuf {
        short sem_num;
        short sem_op;
        short sem_flg;
    }

    第一个成员,sem_num,是信号量数目,通常为0,除非我们正在使用一个信号量数组。sem_op成员是信号量的变化量值。(我们可以以任何量改变信号量值,而不只是1)通常情况下中使用两个值,-1是我们的P操作,用来等待一个信号量变得可用,而+1是我们的V操作,用来通知一个信号量可用。

    最后一个成员,sem_flg,通常设置为SEM_UNDO。这会使得操作系统跟踪当前进程对信号量所做的改变,而且如果进程终止而没有释放这个信号量,如果信号量为这个进程所占有,这个标记可以使得操作系统自动释放这个信号量。将sem_flg设置为SEM_UNDO是一个好习惯,除非我们需要不同的行为。如果我们确实变我们需要一个不同的值而不是SEM_UNDO,一致性是十分重要的,否则我们就会变得十分迷惑,当我们的进程退出时,内核是否会尝试清理我们的信号量。

    semop的所用动作会同时作用,从而避免多个信号量的使用所引起的竞争条件。我们可以在手册页中了解关于semop处理更为详细的信息。
    www.

    semctl

    semctl函数允许信号量信息的直接控制:

    int semctl(int sem_id, int sem_num, int command, ...);

    第一个参数,sem_id,是由semget所获得的信号量标识符。sem_num参数是信号量数目。当我们使用信号量数组时会用到这个参数。通常,如果这是第一个且是唯一的一个信号量,这个值为0。command参数是要执行的动作,而如果提供了额外的参数,则是unionsemun,根据X/OPEN 规范,这个参数至少包括下列参数:

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

    许多版本的Linux在头文件(通常为sem.h)中定义了semun联合,尽管X/Open确认说我们必须定义我们自己的联合。如果我们发现我们确实需要定义我们自己的联合,我们可以查看semctl手册页了解定义。如果有这样的情况,建议使用手册页中提供的定义,尽管这个定义与上面的有区别。

    有多个不同的command值可以用于semctl。在这里我们描述两个会经常用到的值。要了解semctl功能的详细信息,我们应该查看手册页。

    这两个通常的command值为:

    SETVAL:用于初始化信号量为一个已知的值。所需要的值作为联合semun的val成员来传递。在信号量第一次使用之前需要设置信号量。
    IPC_RMID:当信号量不再需要时用于删除一个信号量标识。

    semctl函数依据command参数会返回不同的值。对于SETVAL与IPC_RMID,如果成功则会返回0,否则会返回-1。


    信号量与共享内存的共同使用例子:

    write 端:

     

    01.#include <stdio.h>
    02.#include <stdlib.h>
    03.#include <string.h>
    04.#include <sys/types.h>
    05.#include <sys/ipc.h>
    06.#include <sys/shm.h>
    07.#include <errno.h>
    08.#include "sem.h"
    09. 
    10.typedef struct
    11.{
    12.char buf[1024];
    13.}memory;
    14. 
    15.int main(int argc, const char *argv[])
    16.{
    17.key_t key;
    18.memory *p = NULL;
    19.int shmid;
    20.int create_flag = 0;
    21.int sem_id;
    22.if ((key = ftok("."'a')) < 0)
    23.{
    24.perror("failed to get key");
    25.exit(-1);
    26.}
    27. 
    28.if ((sem_id = semget(key, 1, 0666 | IPC_CREAT | IPC_EXCL)) < 0)
    29.{
    30.if (errno == EEXIST)
    31.{
    32.if ((sem_id = semget(key, 1, 0666)) < 0)
    33.{
    34.perror("failed to semget");
    35.exit(-1);
    36.}
    37.}
    38.}
    39. 
    40.init_sem(sem_id, 0);
    41.if ((shmid = shmget(key, sizeof(memory), 0666 | IPC_CREAT | IPC_EXCL)) < 0)
    42.{
    43.if (errno == EEXIST)
    44.{
    45.if ((shmid = shmget(key, sizeof(memory), 0666)) < 0)
    46.{
    47.perror("failed to shmget memory");
    48.exit(-1);
    49.}
    50.}
    51.else
    52.{
    53.perror("failed to shmget");
    54.exit(-1);
    55.}
    56.}
    57.else
    58.create_flag = 1;
    59.if ((p = shmat(shmid, NULL, 0)) == (void *)(-1))
    60.{
    61.perror("failed to shmat memory");
    62.exit(-1);
    63.}
    64.while(1)
    65.{
    66.printf(">");
    67.fgets(p->buf, sizeof(p->buf), stdin);
    68.p->buf[strlen(p->buf) - 1] = 0;
    69.sem_v(sem_id);
    70.if (strncmp(p->buf, "quit", 4) == 0)
    71.break;
    72.}
    73. 
    74.if (create_flag == 1)
    75.{
    76.if (shmdt(p) < 0)
    77.{
    78.perror("failed to shmdt memory");
    79.exit(-1);
    80.}
    81. 
    82.if (shmctl(shmid, IPC_RMID, NULL) == -1)
    83.{
    84.perror("failed to delete share memory");
    85.exit(-1);
    86.}
    87.delete_sem(sem_id);
    88.}
    89.return 0;
    90.}

    read 端:

     

    01.#include <stdio.h>
    02.#include <stdlib.h>
    03.#include <string.h>
    04.#include <sys/types.h>
    05.#include <sys/ipc.h>
    06.#include <sys/shm.h>
    07.#include <errno.h>
    08.#include "sem.h"
    09. 
    10.typedef struct
    11.{
    12.char buf[1024];
    13.}memory;
    14. 
    15.int main(int argc, const char *argv[])
    16.{
    17.key_t key;
    18.int shmid;
    19.memory *p = NULL;
    20.int create_flag = 0;
    21.int sem_id;
    22.if ((key = ftok("."'a')) < 0)
    23.{
    24.perror("failed to get key");
    25.exit(-1);
    26.}
    27.if ((sem_id = semget(key, 1, 0666 | IPC_CREAT | IPC_EXCL)) < 0)
    28.{
    29.if (errno == EEXIST)
    30.{
    31.if ((sem_id = semget(key, 1, 0666)) < 0)
    32.{
    33.perror("failed to semget");
    34.exit(-1);
    35.}
    36.}
    37.}
    38.init_sem(sem_id, 0);
    39. 
    40.if ((shmid = shmget(key, sizeof(memory), 0666 | IPC_CREAT | IPC_EXCL)) < 0)
    41.{
    42.if (errno == EEXIST)
    43.{
    44.if ((shmid = shmget(key, sizeof(memory), 0666)) < 0)
    45.{
    46.perror("failed to create share memory");
    47.exit(-1);
    48.}
    49.}
    50.else
    51.{
    52.perror("failed to shmget");
    53.exit(-1);
    54.}
    55.}
    56.else
    57.create_flag = 1;
    58. 
    59.if ((p = shmat(shmid, NULL, 0)) == (void *)(-1))
    60.{
    61.perror("failed to shmat");
    62.exit(-1);
    63.}
    64. 
    65.while(1)
    66.{
    67.sem_p(sem_id);
    68.if (strncmp(p->buf, "quit", 4) == 0)
    69.break;
    70.printf("recv: %s\n", p->buf);
    71. 
    72.}
    73. 
    74.if (create_flag == 1)
    75.{
    76.if (shmdt(p) < 0)
    77.{
    78.perror("failed to shmdt");
    79.exit(-1);
    80.}
    81. 
    82.if (shmctl(shmid, IPC_RMID, NULL) == -1)
    83.{
    84.perror("failed to delete share memory");
    85.exit(-1);
    86.}
    87.delete_sem(sem_id);
    88.}
    89.return 0;
    90.}

    信号量的封装:

     

    01.#include <stdio.h>
    02.#include <stdlib.h>
    03.#include <sys/types.h>
    04.#include <sys/ipc.h>
    05.#include <sys/sem.h>
    06.#include <unistd.h>
    07. 
    08.void init_sem(int int );
    09.void delete_sem(int );
    10.void sem_p(int );
    11.void sem_v(int );
    12. 
    13.union semun
    14.{
    15.int val;
    16.struct semid_ds *buf;
    17.unsigned short *array;
    18.};
    19. 
    20.void init_sem(int sem_id, int init_value)
    21.{
    22.union semun sem_union;
    23.sem_union.val = init_value;
    24. 
    25.if (semctl(sem_id, 0, SETVAL, sem_union) < 0)
    26.{
    27.perror("failed to init_sem");
    28.exit(-1);
    29.}
    30.return ;
    31.}
    32. 
    33.void delete_sem(int sem_id)
    34.{
    35.union semun sem_union;
    36.if (semctl(sem_id, 0, IPC_RMID, sem_union) < 0)
    37.{
    38.perror("failed to delete_sem");
    39.exit(-1);
    40.}
    41.return ;
    42.}
    43.void sem_p(int sem_id)
    44.{
    45.struct sembuf sem_b;
    46.sem_b.sem_num = 0;
    47.sem_b.sem_op = -1;
    48.sem_b.sem_flg = SEM_UNDO;
    49.if (semop(sem_id, &sem_b, 1) < 0)
    50.{
    51.perror("failed to sem_p");
    52.exit(-1);
    53.}
    54.return;
    55.}
    56.void sem_v(int sem_id)
    57.{
    58.struct sembuf sem_b;
    59.sem_b.sem_num = 0;
    60.sem_b.sem_op = 1;
    61.sem_b.sem_flg = SEM_UNDO;
    62. 
    63.if (semop(sem_id, &sem_b, 1) < 0)
    64.{
    65.perror("failed to sem_v");
    66.exit(-1);
    67.}
    68.return ;
    69.}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多