【问题标题】:Processes with group of 2 semaphores and shared memory具有 2 个信号量和共享内存组的进程
【发布时间】:2020-09-09 05:50:44
【问题描述】:

我编写了一个包含两个进程的程序:第一个包含一组两个信号量,并创建子进程读取共享内存段中的所有数据并打印它们。

第二一个中,子进程使用计算函数计算数据,当计算所有数据时返回0。它通过共享内存段将它们传输给父代。

写入数据:

  • 在第一个信号量上,孩子发出 P,父母发出 V。

  • 在第二个信号量上,孩子发出 V,父母发出 P。

但是由于我是这个主题的新手,并且仍然难以理解,所以我似乎做错了什么,因为它没有按应有的方式工作。

这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <semaphore.h>
#include <sys/shm.h>
#include <errno.h>
#include <sys/wait.h>

int sum =0;

int compute(int data){
    sum += data;
    return sum;
}

int main(){
    int i;
    int shm_id;
    int data;
    pid_t pid;
    key_t shm_key;
    sem_t *sem;
    // unsigned int sem_value =2;
    shm_key = ftok("/dev/null", 65);
    shm_id = shmget(shm_id, sizeof(int), 0644 | IPC_CREAT);
    if (shm_id < 0){
        perror("shmgget");
        exit(EXIT_FAILURE);
    }
    // data = shmat(shm_id, NULL, 0);
    sem = sem_open("semaphore", O_CREAT | O_EXCL, 0644, 2);

    for (i = 0; i < 2; i++){
        pid = fork();
        if (pid < 0)
        {
            perror("fork");
            sem_unlink("semaphore");
            sem_close(sem);
            exit(EXIT_FAILURE);
        }
        else if (pid == 0)
        {
            break;
        }
    }
    if (pid == 0)
    {
        puts("Enter the data:");
        scanf("%d", &data);
        //child process
        sem_wait(sem);
        printf("Child - %d is in critical section\n", i);
        sleep(1);

        puts("Enter the data:");
        scanf("%d", &data);
        // *shrd_value += data;
        printf("Child - %d: new value of data = %d\n", i, data);
        printf("Child - %d: sum of whole data by far = %d\n", i, compute(data));
        sem_post(sem);
        exit(EXIT_SUCCESS);
    }
    else if (pid > 0)
    {
        //parent process
        while (pid = waitpid(-1, NULL, 0))
        {
            if (errno == ECHILD)
            {
                break;
            }
        }
        puts("All children exited");
        shmdt(&data);
        shmctl(shm_id, IPC_RMID, 0);
        sem_unlink("semaphore");
        sem_close(sem);         
        exit(0);
    }
}

输出:

Enter the data:
Enter the data:
2
Child - 0 is in critical section
1Enter the data:

Child - 1 is in critical section
Enter the data:
3
Child - 0: new value of data = 3
Child - 0: sum of whole data by far = 3
2
Child - 1: new value of data = 2
Child - 1: sum of whole data by far = 2
All children exited

【问题讨论】:

    标签: c fork posix semaphore shared-memory


    【解决方案1】:

    我还修改了它们写入共享内存的方式:它们直接写入您的代码中缺少的 shmat 调用给出的地址。 我已经修复了一些错误并简化了代码(删除了数组 - 添加了详细的日志记录,尤其是在进入关键部分之前和之后):

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <fcntl.h>
    #include <semaphore.h>
    #include <sys/shm.h>
    #include <errno.h>
    #include <sys/wait.h>
    
    int main(){
        int i;
        int shm_id;
        pid_t pid;
        int *addr; 
        int data;
        pid_t current_pid;
        key_t shm_key;
        sem_t *sem;
    
        shm_key = ftok("/dev/null", 65);
        shm_id = shmget(shm_key, sizeof(int), 0644 | IPC_CREAT);
        if (shm_id < 0){
            perror("shmget");
            exit(EXIT_FAILURE);
        }
    
        sem_unlink("semaphore");
        sem = sem_open("semaphore", O_CREAT, 0644, 1);
        if (sem == SEM_FAILED) {
            perror("sem_open");
            exit(EXIT_FAILURE);
        } 
    
        addr = (int *) shmat(shm_id, (void *) 0, 0);   
        if (addr == (void *) -1) {
            perror("shmat");
            exit(EXIT_FAILURE);
        }
        *addr = 0;
    
        for (i = 0; i < 2; i++){
            pid = fork();
            if (pid < 0)
            {
                perror("fork");
                sem_close(sem);
                sem_unlink("semaphore");
                exit(EXIT_FAILURE);
            }
        }
    
    
        if (pid == 0)
        {
        current_pid = getpid();
            printf("Child %d: waiting for critical section \n", current_pid);
            sem_wait(sem);
            printf("Child %d: enters in critical section \n", current_pid);
            printf("child %d: Enter the data:\n", current_pid);
            scanf("%d", &data);
            printf("Child %d: new value of data = %d\n", current_pid, data);
            printf("Child %d: sum of whole data so far = %d\n", current_pid, *addr += data);
            sem_post(sem);
        printf("Child %d exits from critical section\n", current_pid);
            exit(EXIT_SUCCESS);
        }
        else if (pid > 0)
        {
            //parent process
            while (pid = waitpid(-1, NULL, 0))
            {
                if (errno == ECHILD)
                {
                    break;
                }
            }
            puts("All children exited");
            shmdt(addr);
            shmctl(shm_id, IPC_RMID, 0);
            sem_close(sem);         
            sem_unlink("semaphore");
            exit(0);
        }
    
        exit(0);
    }
    

    请注意,信号量初始值必须为 1 才能为 2 个进程提供真正的临界区。

    我还删除了睡眠调用,我们可以看到其中一个进程正在等待:

    Child 22514: waiting for critical section 
    Child 22514: enters in critical section 
    child 22514: Enter the data:
    Child 22515: waiting for critical section 
    333
    Child 22514: new value of data = 333
    Child 22514: sum of whole data so far = 333
    Child 22514 exits from critical section
    Child 22515: enters in critical section 
    child 22515: Enter the data:
    666
    Child 22515: new value of data = 666
    Child 22515: sum of whole data so far = 999
    Child 22515 exits from critical section
    All children exited
    All children exited
    

    【讨论】:

    • 非常感谢,我比较了两个代码并理解了我错过和犯错的部分。那么,这段代码中的消费者和生产者问题怎么样?就像,而设置为共享内存的生产者值和消费者不获取任何值并从共享内存中返回第一个值。如果没有可用的值,那么它将等待程序等待生产者存储该值。怎么链接?
    • IMO 这是一个非常简化的生产者/消费者系统:好的,子进程是生产者,父进程是消费者,但在这段代码中,它不对数据做任何事情。:它确实并没有真正消耗它,因为它知道子进程已经退出,它可以在没有信号量的情况下读取数据。在通常的生产者/消费者系统中,我们将始终运行守护进程(父进程和子进程),并在子进程和父进程之间持续进行数据处理。
    • 好吧,好吧。我试图从头开始编写程序,与这个程序无关,但它没有正常工作,尽管它没有错误标志。我可以展示吗?在尝试学习该主题(消费者/生产者)时,我很难过。
    • 是的,你可以展示它,我会在这个周末尝试看看。
    • 非常感谢!我将把它发布在答案部分。
    【解决方案2】:

    这是生产者和消费者进程的代码

    #include <stdio.h> 
    #include <stdlib.h>
    #include <fcntl.h>         // O_CREAT, O_EXEC
    #include <errno.h>         // errno, ECHILD     
    #include <unistd.h>
    #include <sys/shm.h>       // shmat(), IPC_RMID
    #include <sys/wait.h> 
    #include <semaphore.h>     // sem_open(), sem_destroy(), sem_wait()...
    #include <sys/types.h>     // key_t, sem_t, pid_t
    #include <pthread.h>
    
    #define BUFF 10
    
    typedef struct data{
        int buff[BUFF];
        int size;
        int index;
    }DATA;
    
    int main(int argc, char const *argv[])
    {
        sem_t *full, *empty, *access;
        key_t shm_key;
        int shm_id;
        full = sem_open ("fullname", O_CREAT , 0644, 15); 
        empty = sem_open ("empty", O_CREAT , 0644, 0);
        access = sem_open ("access", O_CREAT , 0644, 1);
    
        if (argc!=2)
        {
            exit(1);
        }
    
        int value=atoi(argv[1]);
    
        //initialize a shared variable in shared memory
        shm_key = ftok("/dev/null", 60);
        shm_id = shmget(shm_key, sizeof(DATA), 0);
        // shared memory error check
        if (shm_id < 0){
            shm_id = shmget(shm_key, sizeof(DATA), 0644 | IPC_CREAT);
            DATA *data = (DATA*) shmat (shm_id, NULL, 0);
            data->size=0;
            data->index=0; //index 
        }
        printf("Shared memory id: %d\n",shm_id );
    
    
        printf("Checking buffer...,\n");
        //If in the buffer have free space then will wait for consumer to consume the data\n"
        sem_wait(empty);
    
        printf("\nLocking buffer to produce data\n");
        sem_wait(access);
    
    
        //initialize a shared variable in shared memory
        shm_key = ftok("/dev/null", 60);
        shm_id = shmget(shm_id, sizeof(DATA), 0644 | IPC_CREAT);
        // shared memory error check
        if (shm_id < 0){
            perror("semaphore");
            exit(EXIT_FAILURE);
        }
    
        //Shared variable  
        DATA *data = (DATA*) shmat (shm_id, NULL, 0);
        int index=(data->size + data->index) % 15;
    
        data->buff[index]=value;
        data->size++;
        printf("%d is located in %d on the buffer\n",value,index );
    
    
    
        //consusming
    
        // attach data to shared memory
    
        index=data->index;
        value=data->buff[index];
    
        printf("%d now consumed\n",value );
        data->size--;
        data->index++;
    
    
    
        sem_post(access);
        sem_post(full);
    
    
    
        return 0;
    }
    

    【讨论】:

    • 如何启动生产者和消费者?我建议将有关此的 cmets 添加为文件头。我还建议您使用 1 个例程名称生产者和 1 个例程名称消费者来构建代码。为什么你有 2 个共享内存段?您是否正在实施众所周知的算法?如果是的话(如果在代码中有一些 cmets 会很好)。否则看看en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem中的第二个算法
    • @pifor 非常感谢您的帮助。我已经解决了,并将消费者和生产者进程写在不同的文件中,我猜它工作了。
    猜你喜欢
    • 1970-01-01
    • 2012-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-27
    • 2018-09-30
    • 2010-10-26
    相关资源
    最近更新 更多