当信号量值为0时写入共享内存会导致程序在C,ubuntu中冻结

flseospp  于 2022-12-03  发布在  其他
关注(0)|答案(1)|浏览(138)

我正在为大学作业编写一个多进程项目的操作系统,我遇到了一个奇怪的问题。当信号量值为0时,写入共享内存的特定部分会导致我的程序冻结。
更具体地说,当我第一次运行父进程的可执行文件时,第一个子进程只向shm_segment_pointer-〉content所连接的内存部分写入一次,然后下一个子进程将在写入同一部分之前冻结。然后在所有后续的运行中,即使是第一个子进程也无法写入该内存段,在写入之前冻结。
用于运行的命令:gcc父项. c-o父项gcc子项. c-o子项./父项
parent.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

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

#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_ */

输出:51200段大小:50正在测试段编号的赋值...成功。正在测试字符串的赋值...
如前所述,程序不会结束,它会冻结在那里,如果不强制结束,它将无法继续。
我试着删除信号量,这样就解决了冻结问题,但这不是我想要的行为。我还试着延迟段的分离,但没有任何改变。唯一起作用的是完全重组了我的项目,它不再使用结构体来存储段信息。

g2ieeal7

g2ieeal71#

你有几个形式上的错误,可能会给你带来麻烦,也可能不会,正如对这个问题的评论中所描述的那样。但是你的主要问题与信号量没有特别的关系。它是这样的...

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

...对于存储在共享内存中的对象是毫无意义的。
具体来说,将指针存储在进程之间共享的内存中几乎是没有意义的。将指针放在共享内存中允许其他进程看到 * 指针 *,但不能看到它所指向的任何东西。即使被指向的对象也在共享内存段中,也不行,因为不能保证每个进程都将该段附加在相同的地址上。
更重要的是,您的特定指针甚至没有初始化为指向任何位置,您的子进程试图将数据复制到它所指向的任何随机位置。
您可能希望声明一个数组而不是一个指针:

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

这样就为共享内存段中的内容腾出了空间,* 和 * 在每个子段中为您提供了指向该内容的有效指针。

相关问题