简体   繁体   English

在信号量值为 0 时写入共享 memory 会导致程序在 C、ubuntu 中冻结

[英]Writing into shared memory while semaphore value is 0 causes program to freeze in C, ubuntu

I'm writing a multi-process project for a university assignment in operating systems and I've come across a strange issue.我正在为操作系统的大学作业编写一个多进程项目,我遇到了一个奇怪的问题。 Writing into a specific part of shared memory while the semaphore value is 0 causes my program to freeze.在信号量值为 0 时写入共享 memory 的特定部分会导致我的程序冻结。

More specifically, the first time I run the executable of parent, the first child process writes into the part of the memory attached to shm_segment_pointer->content once, then the next child process to reach that part of the program freezes the moment before it writes into the same part.更具体地说,我第一次运行 parent 的可执行文件时,第一个子进程写入附加到 shm_segment_pointer->content 的 memory 的部分一次,然后下一个到达该程序部分的子进程在它写入之前冻结那一刻到同一部分。 Then in all subsequent runs, not even the first child is able to write into that memory segment, freezing up before doing so.然后在所有后续运行中,即使是第一个孩子也无法写入 memory 段,在这样做之前冻结。

commands used to run: gcc parent.c -o parent gcc child.c -o child./parent用于运行的命令:gcc parent.c -o parent gcc child.c -o child./parent

parent.c父母.c

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

#include "utilities.h"


#define _OPEN_SYS_ITOA_EXT
#define N 4
#define REQUEST_HANDLING_REQ (unsigned long)1000
#define CLIENT_PATH_BUFSIZE 255

#define INITIAL_VALUE 1

void path_to_child(char* buffer){
    unsigned long dir_len;
    getcwd(buffer, CLIENT_PATH_BUFSIZE);
    dir_len = strlen(buffer);
    strcpy(buffer + dir_len, "/child");
}


int main(int argc, char* argv[]){
    char* newargv[2];

    char child_exe[CLIENT_PATH_BUFSIZE];
    unsigned int file_line_size, seg_amount;
    sem_t *main_sem, *rw_sem;
    int i = 0;
    pid_t pid = 1;
    int shmid_struct, shmid_text;
    unsigned int segment_size = 50;

    srand(time(NULL));
    sem_unlink(SEM_NAME);
    sem_unlink(RW_SEM_NAME);

   
    /*Initialize shared memory*/
    shmid_struct = shmget((key_t)SHM_KEY_SEG_STRUCT, sizeof(shm_seg), SHM_SEGMENT_PERM | IPC_CREAT);
    if (shmid_struct == -1) {
        fprintf(stderr, "shmget failed\n");
        exit(EXIT_FAILURE);
    }
    shmid_text = shmget((key_t)SHM_KEY_SEG_TEXT, SHM_LINE_SIZE * segment_size * sizeof(char), SHM_SEGMENT_PERM | IPC_CREAT);
    if (shmid_struct == -1) {
        fprintf(stderr, "shmget failed\n");
        exit(EXIT_FAILURE);
    }

    /*Init semaphores*/
    main_sem = sem_open(SEM_NAME, O_CREAT | O_EXCL, SEM_PERMS, INITIAL_VALUE);
    if(SEM_FAILED == main_sem){
        perror("sem_open error on main sem");
        exit(EXIT_FAILURE);
    }
    rw_sem = sem_open(RW_SEM_NAME, O_CREAT | O_EXCL, SEM_PERMS, INITIAL_VALUE);
    if(SEM_FAILED == rw_sem){
        perror("sem_open error on rw_sem");
        exit(EXIT_FAILURE);
    }

    /* Initialize the info needed for child functions*/

    newargv[0] = "child";                           //The name of the child process

    newargv[1] = NULL;
    path_to_child(child_exe);
    fflush(stdout);
    for( i = 0; i < N; i++ ){
        if( 0 > (pid = fork())){
            perror("Could not fork, ending process...");
            exit(1);
        } else if(0 == pid){
            //Initiate child process
            execv(child_exe,newargv);
            //If exec failed:
            perror("exec2: execv failed");
            exit(2);
        }
    }

        
    /**************************************Cleanup Section******************************************/
    /*Close file descriptors*/

    /*Wait for child processes to finish*/
    for( i = 0; i < N; i++ ){
        pid = wait(NULL);
        if(pid == -1){
            perror("wait failed");
        }

    }
    /*Clean up shared memory*/
    if (shmctl(shmid_text, IPC_RMID, 0) == -1) {
        fprintf(stderr, "shmctl(IPC_RMID) failed\n");
        exit(EXIT_FAILURE);
    }
    if (shmctl(shmid_struct, IPC_RMID, 0) == -1) {
        fprintf(stderr, "shmctl(IPC_RMID) failed\n");
        exit(EXIT_FAILURE);
    }

    /*Unlink semaphore, removing it from the file system only after the child processes are done*/
    if(sem_unlink(SEM_NAME) < 0){
        perror("sem_unlink failed");
    }
    if(sem_unlink(RW_SEM_NAME) < 0){
        perror("sem_unlink failed");
    }
    return 0;
}


child.c孩子.c

int main(int argc, char *argv[]){

    struct timespec sleep_time;
    sem_t *semaphore, *rw_semaphore;
    shm_seg *shm_segment_pointer;
    int ifd, ofd;
    FILE* fptr;
    int shmid_struct, shmid_text;

    /********************************Init section*********************************************/
    srand(time(NULL));

    /*Open semaphore from the semaphore file.*/
    semaphore = sem_open(SEM_NAME, 0);
    if (semaphore == SEM_FAILED) {
        perror("sem_open failed");
        exit(EXIT_FAILURE);
    }
    rw_semaphore = sem_open(RW_SEM_NAME, 0);
    if (rw_semaphore == SEM_FAILED) {
        perror("sem_open failed");
        exit(EXIT_FAILURE);
    }
    setbuf(stdout,NULL);
    /* Make shared memory segment for the . */
    shmid_struct = shmget(SHM_KEY_SEG_STRUCT, sizeof(shm_seg), SHM_SEGMENT_PERM);
    if (shmid_struct == -1) {
        perror("Acquisition");
    }
    shmid_text = shmget(SHM_KEY_SEG_TEXT, seg_size * SHM_LINE_SIZE * sizeof(char), SHM_SEGMENT_PERM);
    if (shmid_text == -1) {
        perror("Acquisition");
    }
    /* Attach the segments. */
    shm_segment_pointer = (shm_seg*)shmat(shmid_struct, NULL, 0);
    if ( shm_segment_pointer == (void *) -1) { 
        perror("Attachment of segment"); 
        exit(2);
    }
    shm_segment_pointer->content = (char*)shmat(shmid_text, NULL, 0);
    if ( shm_segment_pointer->content == (void *) -1) { 
        perror("Attachment of text"); 
        exit(2);
    }

    /************************************Working Segment************************************************/

    sem_wait(semaphore);
    printf("Testing assignement to seg number...");
    shm_segment_pointer->seg_num = 1;
    printf("Successful.\nTesting assignment to string...");
    strcpy( shm_segment_pointer->content, "ABCD");
    printf("shm contents are: %s\n",shm_segment_pointer->content);
    sem_post(semaphore);
    sleep(10);



    if (sem_close(semaphore) < 0)
        perror("sem_close(1) failed");
    if( sem_close(rw_semaphore) < 0)
        perror("sem_close(1) failed");
    /* detach from the shared memory segment: */
    if(shmdt(shm_segment_pointer->content) == -1) {
        perror("shmdt on text point failed");
        exit(1);
    }
    if (shmdt(shm_segment_pointer) == -1) {
    perror("shmdt on segment pointer failed");
    exit(1);
 

    return 0;
}

utilities.h公用事业.h

#ifndef _UTILITIES_H_
#define _UTILITIES_H_

#include <stdlib.h>

#define SEM_NAME "SM"
#define RW_SEM_NAME "RW_SM"
#define OUTPUT_FILE "testoutput.txt"

#define SHM_LINE_SIZE 1024
#define SHM_SEGMENT_PERM 0666
#define SHM_KEY_SEG_STRUCT 01234
#define SHM_KEY_SEG_TEXT 02345
#define SEM_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)



typedef struct shared_memory_seg_tag{
    int seg_num;
    char* content;
} shm_seg;






#endif /* _UTILITIES_H_ */

Output: 51200 seg size:50 Testing assignement to seg number...Successful. Output:51200 段大小:50 测试段号的分配...成功。 Testing assignment to string...测试对字符串的分配...

As stated, the program doesn't end, it freezes there and won't continue without forcing it to end.如前所述,该程序不会结束,它会冻结在那里并且不会在不强制结束的情况下继续。

I tried removing the semaphores, which fixed the freezing issue but was not the desired behaviour.我尝试删除信号量,这解决了冻结问题,但不是预期的行为。 I also tried delaying the detachment of the segments, which didn't change anything.我还尝试延迟分段的分离,但没有任何改变。 The only thing that work was completely restructuring my project, which no longer uses a struct to store the segment information.唯一有用的是完全重构我的项目,它不再使用结构来存储段信息。

You have a couple of errors in form that may or may not actually be causing you trouble, as described in comments on the question.如对问题的评论中所述,您在表格中有几个错误可能会或可能不会真正给您带来麻烦。 But your main issue has nothing in particular to do with the semaphores.但是您的主要问题与信号量没有特别关系。 It is that this...就是这个...

 typedef struct shared_memory_seg_tag{ int seg_num; char* content; } shm_seg;

... is nonsense for an object stored in shared memory. ...对于存储在共享 memory 中的 object 来说是无稽之谈。

Specifically, it pretty much never makes sense to store pointers in memory shared between processes.具体来说,在进程之间共享的 memory 中存储指针几乎没有任何意义。 Putting a pointer in shared memory allows other processes to see the pointer , but not whatever, if anything, it points to.将指针放入共享 memory 允许其他进程看到该指针,但看不到它指向的任何内容(如果有的话)。 Not even if the pointed-to object is also in the shared memory segment, because the segment is not guaranteed to be attached at the same address in each process.即使指向的 object 也在共享的 memory 段中也不行,因为不能保证该段在每个进程中附加到相同的地址。

What's more, your particular pointer isn't even initialized to point to anything in the first place.更重要的是,您的特定指针甚至没有初始化为首先指向任何东西。 Your child processes are attempting to copy data to whatever random place it points.您的子进程正试图将数据复制到它指向的任何随机位置。

You probably want to declare an array instead of a pointer:您可能想要声明一个数组而不是一个指针:

typedef struct shared_memory_seg_tag{
    int seg_num;
    char content[MAX_CONTENT_SIZE];
} shm_seg;

That makes space for the content available in the shared memory segment, and gives you a valid pointer to it in each child.这为共享 memory 段中的可用内容腾出了空间,为您提供了每个孩子中指向它的有效指针。 Of course, you do have to choose a MAX_CONTENT_SIZE that suits all your needs.当然,您必须选择适合您所有需求的MAX_CONTENT_SIZE

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM