簡體   English   中英

在信號量值為 0 時寫入共享 memory 會導致程序在 C、ubuntu 中凍結

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

我正在為操作系統的大學作業編寫一個多進程項目,我遇到了一個奇怪的問題。 在信號量值為 0 時寫入共享 memory 的特定部分會導致我的程序凍結。

更具體地說,我第一次運行 parent 的可執行文件時,第一個子進程寫入附加到 shm_segment_pointer->content 的 memory 的部分一次,然后下一個到達該程序部分的子進程在它寫入之前凍結那一刻到同一部分。 然后在所有后續運行中,即使是第一個孩子也無法寫入 memory 段,在這樣做之前凍結。

用於運行的命令:gcc parent.c -o parent gcc child.c -o child./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;
}


孩子.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;
}

公用事業.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 段大小:50 測試段號的分配...成功。 測試對字符串的分配...

如前所述,該程序不會結束,它會凍結在那里並且不會在不強制結束的情況下繼續。

我嘗試刪除信號量,這解決了凍結問題,但不是預期的行為。 我還嘗試延遲分段的分離,但沒有任何改變。 唯一有用的是完全重構我的項目,它不再使用結構來存儲段信息。

如對問題的評論中所述,您在表格中有幾個錯誤可能會或可能不會真正給您帶來麻煩。 但是您的主要問題與信號量沒有特別關系。 就是這個...

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

...對於存儲在共享 memory 中的 object 來說是無稽之談。

具體來說,在進程之間共享的 memory 中存儲指針幾乎沒有任何意義。 將指針放入共享 memory 允許其他進程看到該指針,但看不到它指向的任何內容(如果有的話)。 即使指向的 object 也在共享的 memory 段中也不行,因為不能保證該段在每個進程中附加到相同的地址。

更重要的是,您的特定指針甚至沒有初始化為首先指向任何東西。 您的子進程正試圖將數據復制到它指向的任何隨機位置。

您可能想要聲明一個數組而不是一個指針:

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

這為共享 memory 段中的可用內容騰出了空間,為您提供了每個孩子中指向它的有效指針。 當然,您必須選擇適合您所有需求的MAX_CONTENT_SIZE

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM