C系统v信号量不锁定关键区域

Posted

技术标签:

【中文标题】C系统v信号量不锁定关键区域【英文标题】:C system v Semaphore not locking critical region 【发布时间】:2019-05-03 14:58:11 【问题描述】:

我有一个代码从共享内存中读取一个整数,然后在子进程中递增该数字。我正在使用信号量来锁定这个关键区域,以便只有在没有其他进程不增加整数的情况下才会增加整数。所以我得到了一个稳定的整数值。

我为此使用了 SYSTEM V Semaphore,但是我无法使其工作,因为看起来我对这些函数的使用没有任何作用。

该程序仅生成 100 个进程,其中每个进程将共享内存中的整数加 1。(最初由另一个程序创建的共享内存段,如果您也需要,请告诉我!)

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

#define FIFO_PATH "/tmp/RESULT_FIFO"
#define PROC_NUM 10
#define MAX_ITERATIONS 1
#define SHM_SIZE 1024
#define SHM_KEY 23423

int shmid, *shmdata, semid;
struct sembuf semaphore;

int main() 
    FILE *fp_fifo;
    /* Initialize Semaphore */
    semid = semget (2134L, 0, IPC_PRIVATE);
    if(semid <0) 
        semid = semget (2134, 1, IPC_CREAT | IPC_EXCL | 0666);
        if (semid < 0) 
            perror("semget()");
            exit(EXIT_FAILURE);
        
    
    semctl(semid, 0, SETVAL, (int)1);
    shmid = shmget(234234, sizeof(int),  0777);
    if(shmid == -1) 
        perror("shmget()");
        exit(EXIT_FAILURE);
    
    shmdata = shmat(shmid, 0, 0);
    if(shmdata == -1) 
        perror("shmat()");
        exit(EXIT_FAILURE);
    
    printf("key is53 %i \n", *shmdata);
    for (int i = 0; i < 100; ++i) 
        int t = fork();
        if(t > 0) 
            /*parent*/
         else if(t == -1) 
            perror("fork()");
         else if(t == 0)  
            /* Child*/
            semaphore.sem_op  = -1;
            semaphore.sem_num = 0;
            semaphore.sem_flg = SEM_UNDO;
            if(semop(semid, &semaphore, 1) == -1) 
                perror("semop()");
                exit(EXIT_FAILURE);
            

            *shmdata=*shmdata+1;
            semaphore.sem_op  = 1;
            if(semop(semid, &semaphore, 1) == -1) 
                perror("semop()");
                exit(EXIT_FAILURE);
            
            return EXIT_SUCCESS;
        
    
    wait(0);
    printf("key is53 %i \n", *shmdata);

    if((fp_fifo = fopen(FIFO_PATH, "w")) == NULL) 
        perror("fopen");
        exit(EXIT_FAILURE);
    

    fprintf(fp_fifo, "%d", *shmdata);
    shmdata = 0;
    shmdt(shmdata);
    return EXIT_SUCCESS;

【问题讨论】:

您使用 Sys V 信号量而不是 POSIX 信号量是否有原因?在我看来,后者的界面更好。 我一直认为 Sys V-crew 是 gobbledygook。 是的,我需要使用 sysV, 没人能解决我的问题吗? 【参考方案1】:

我发现错误是因为 wait() 没有正常工作。 信号量正常工作,但未正确使用 wait(NULL)。这是我对如何使用 system V 信号量的简单示例的更正版本:

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

#define FIFO_PATH "/tmp/RESULT_FIFO"
#define PROC_NUM 10
#define MAX_ITERATIONS 1
#define SHM_SIZE 1024
#define SHM_KEY 23423

int shmid, *shmdata, semid;
struct sembuf semaphore;

int main() 
    FILE *fp_fifo;
    /* Initialize Semaphore */
    semid = semget (2134L, 0, IPC_PRIVATE);
    if(semid <0) 
        semid = semget (2134, 1, IPC_CREAT | IPC_EXCL | 0666);
        if (semid < 0) 
            perror("semget()");
            exit(EXIT_FAILURE);
        
    
    semctl(semid, 0, SETVAL, (int)1);
    shmid = shmget(234234, sizeof(int),  0777);
    if(shmid == -1) 
        perror("shmget()");
        exit(EXIT_FAILURE);
    
    shmdata = shmat(shmid, 0, 0);
    if(shmdata == -1) 
        perror("shmat()");
        exit(EXIT_FAILURE);
    
    printf("key is46 %i \n", *shmdata);
    for (int i = 0; i < 100; ++i) 
        int t = fork();
        if(t > 0) 
            /*parent*/
            wait(NULL);
         else if(t == -1) 
            perror("fork()");
         else if(t == 0)  
            /* Child*/
            semaphore.sem_op  = -1;
            semaphore.sem_num = 0;
            semaphore.sem_flg = SEM_UNDO;
            if(semop(semid, &semaphore, 1) == -1) 
                perror("semop()");
                exit(EXIT_FAILURE);
            


            *shmdata= *shmdata+1;
           // printf("key is65 %i \n", *shmdata);
            semaphore.sem_op  = 1;
            if(semop(semid, &semaphore, 1) == -1) 
                perror("semop()");
                exit(EXIT_FAILURE);
            
            return EXIT_SUCCESS;
        
    
    printf("key is73 %d \n", *shmdata);

    if((fp_fifo = fopen(FIFO_PATH, "w")) == NULL) 
        perror("fopen");
        exit(EXIT_FAILURE);
    

    fprintf(fp_fifo, "%d", *shmdata);
    shmdata = 0;
    shmdt(shmdata);
    return EXIT_SUCCESS;

【讨论】:

以上是关于C系统v信号量不锁定关键区域的主要内容,如果未能解决你的问题,请参考以下文章

正确销毁命名的 System V 信号量

使用嵌套异步调用锁定

编写高质量代码改善C#程序的157个建议——建议72:在线程同步中使用信号量

linux fcntl文件锁定超时

删除类 UNIX 系统上的所有 SYSTEM V 共享内存和信号量

linux进程间通讯-System V IPC 信号量