我正在为大学作业编写一个多进程项目的操作系统,我遇到了一个奇怪的问题。当信号量值为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正在测试段编号的赋值...成功。正在测试字符串的赋值...
如前所述,程序不会结束,它会冻结在那里,如果不强制结束,它将无法继续。
我试着删除信号量,这样就解决了冻结问题,但这不是我想要的行为。我还试着延迟段的分离,但没有任何改变。唯一起作用的是完全重组了我的项目,它不再使用结构体来存储段信息。
1条答案
按热度按时间g2ieeal71#
你有几个形式上的错误,可能会给你带来麻烦,也可能不会,正如对这个问题的评论中所描述的那样。但是你的主要问题与信号量没有特别的关系。它是这样的...
...对于存储在共享内存中的对象是毫无意义的。
具体来说,将指针存储在进程之间共享的内存中几乎是没有意义的。将指针放在共享内存中允许其他进程看到 * 指针 *,但不能看到它所指向的任何东西。即使被指向的对象也在共享内存段中,也不行,因为不能保证每个进程都将该段附加在相同的地址上。
更重要的是,您的特定指针甚至没有初始化为指向任何位置,您的子进程试图将数据复制到它所指向的任何随机位置。
您可能希望声明一个数组而不是一个指针:
这样就为共享内存段中的内容腾出了空间,* 和 * 在每个子段中为您提供了指向该内容的有效指针。