我正在尝试在我的快速排序中使用子进程,以使左半部分在一个孩子中排序,右半部分在另一个孩子中排序。在shmget实施之前,我已经使它工作了,但是现在,我相信我正在某个地方破坏该数组,因为在打印该数组之后,我的所有值都变为零。抱歉,如果我在某个地方犯了一些愚蠢的错误,我正在尝试学习如何使用fork和shmget,但是遇到了一些麻烦。我试图将文本文件作为命令行参数,并给定分隔符,例如“;”。我必须删除定界符并确定其间的数字,将它们放置在数组中并使用子进程对其进行排序。我可以进行解析,而快速排序也可以,但是现在我尝试实现共享内存时遇到了一些问题。
谢谢
我看了几个不同的示例,但这主要基于的示例是带有fork的mergesorting的geeksforgeeks示例。 https://www.geeksforgeeks.org/concurrent-merge-sort-in-shared-memory/
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "fileParser.h"
#include "dataManagement.h"
int main(int argc, char *argv[]){
char *file = argv[1];
char delimiter = argv[2][0];
MyArray *theArray = getArray(file, delimiter);
size_t SHM_SIZE = theArray->length;
theArray->key = IPC_PRIVATE;
if((theArray->shmid = shmget(theArray->key, SHM_SIZE, IPC_CREAT | 0666)) < 0){
perror("shmget");
_exit(-1);
}
if ((theArray->shm_array = shmat(theArray->shmid, NULL, 0)) == (int *) -1)
{
perror("shmat");
_exit(1);
}
printArray(theArray, theArray->length);
quickSortFork(theArray, 0, theArray->length-1);
printArray(theArray, theArray->length);
if (shmdt(theArray->shm_array) == -1)
{
perror("shmdt");
_exit(1);
}
if (shmctl(theArray->shmid, IPC_RMID, NULL) == -1)
{
perror("shmctl");
_exit(1);
}
return 0;
}
dataManagement.h
#include <unistd.h>
#include <sys/wait.h>
#include "fileParser.h"
int partition(MyArray *arr, int low, int high);
void quickSortFork(MyArray *arr, int low, int high);
void swap(MyArray *arr, int a, int b);
void printArray(MyArray *arr, int length) {
for(int i = 0; i < length; i++){
printf("%d ", arr->shm_array[i]);
}
printf("\n");
}
void quickSortFork(MyArray *arr, int low, int high){
pid_t lpid, rpid;
rpid = fork();
if(low < high){
int partitionIndex = partition(arr,low, high);
if(rpid < 0){
perror("Right child not created.\n");
exit(-1);
} else if(rpid == 0 ){
printf("I am the right child!\tMy process id: %d\n",getpid());
quickSortFork(arr, partitionIndex + 1, high);
exit(EXIT_SUCCESS);
} else {
lpid = fork();
if(lpid < 0){
perror("Left child not created.\n");
} else if (lpid == 0) {
quickSortFork(arr, low, partitionIndex - 1);
printf("I am the left child!\tMy process id: %d\n", getpid());
exit(EXIT_SUCCESS);
}
}
int status;
waitpid(rpid, &status, 0);
waitpid(lpid, &status, 0);
}
}
int partition(MyArray *arr, int low, int high){
int i = low, j = high;
int pivot = arr->shm_array[(low+high)/2];
while(i < j){
while(arr->shm_array[i] < pivot)
i++;
while(arr->shm_array[j] > pivot)
j--;
if(i < j){
swap(arr,i,j);
}
}
return i;
}
void swap(MyArray *arr, int a, int b){
int temp = arr->shm_array[a];
arr->shm_array[a] = arr->shm_array[b];
arr->shm_array[b] = temp;
}
fileParser.h
int findFileLength(FILE *inFile, char delimiter);
int *parseFileToArray(FILE *inFile, char delimiter, int length);
typedef struct {
int shmid;
key_t key;
int length;
int *shm_array;
} MyArray;
MyArray *getArray(char *fileName, char delimiter){
FILE *numberFile = fopen(fileName, "r"); // open for reading
if (numberFile == NULL) // unable to open file
return NULL;
MyArray *array = malloc(sizeof(MyArray));
array->length = findFileLength(numberFile, delimiter);
array->shm_array = parseFileToArray(numberFile, delimiter,array->length);
return array;
}
int findFileLength(FILE *inFile, char delimiter){
char c;
int length = 0;
c = fgetc(inFile);
while(c != EOF){
if(c != delimiter && c != '\n'){
length++;
while((c = fgetc(inFile)) != EOF && c != '\n' && c != delimiter);
} else {
c = fgetc(inFile);
}
}
rewind(inFile); // resets the file pointer to the start
return length;
}
int *parseFileToArray(FILE *inFile, char delimiter, int length){
int *parsedFile = malloc(sizeof(int) * length);
char c;
char *stringInt = malloc(sizeof(char) * 100); // string that is used to combine multiple characters and convert to an integer
int stringIntP = 0, parsedArrayP = 0; // pointers for our arrays, the first is for the string that determines the integer, the second is for our resulting array
c = fgetc(inFile);
while(c != EOF){
if(c != delimiter && c != '\n'){
for(;c != '\n' && c != delimiter; (c = fgetc(inFile)) != EOF){
stringInt[stringIntP++] = c;
}
stringIntP = 0;
parsedFile[parsedArrayP++] = atoi(stringInt); // convert string number to integer value
memset(stringInt, 0, 100); // clear the string that builds the integer value from chars
} else {
c = fgetc(inFile);
}
}
for(int i = 0; i < length; i++){
printf("%d ", parsedFile[i]);
}
printf("\n");
fclose(inFile); // close the file after using
free(stringInt);
return parsedFile;
}
预期的输出:首先传递未排序的数组。然后对数组进行排序。
实际输出:充满0的数组,程序未完成执行
答案 0 :(得分:4)
有几个错误。我终于能够找到所有这些,下面是一个可用的版本。
以下是摘要:
rpid = fork();
在主if
语句的上方上方完成。如果if
为假,则创建一个僵尸进程。sizeof(int) * number_of_elements
partition
函数的调用是在第一个fork
调用之后的 中完成的,因此,两者均被调用父母和孩子,因此他们发生冲突/竞争。fork
调用失败。 (1)如上所述,如果rpid = fork();
语句为假,if (low < high)
必须紧随if
之后才能防止创建僵尸进程。在下面的第(4)节中对此有更多的了解。
(2)您的共享内存区域太小。在最终打印期间会导致段错误。
这是不正确的:
size_t SHM_SIZE = theArray->length;
它必须是:
size_t SHM_SIZE = sizeof(int) * theArray->length;
(3)您是通过调用theArray
在非共享内存中创建getArray
。
它将shm_array
设置为从parseFileToArray
的呼叫。这是非共享内存中的 still 。
稍后,要获取共享区域,请执行以下操作:
theArray->shm_array = shmat(theArray->shmid, NULL, 0)
此返回值shm_array
现在位于共享内存中,但 data 仍然位于{em> old 值中{1}} [再次,在非共享内存中]。指向实际数据的指针永远是 lost 。
要解决此问题,您将需要以下内容:
shm_array
当然,当程序正常运行时,最好将int *shm_array;
if ((shm_array = shmat(theArray->shmid, NULL, 0)) == (int *) -1) {
perror("shmat");
_exit(1);
}
int *oldptr = theArray->shm_array;
for (int idx = 0; idx < theArray->length; ++idx)
shm_array[idx] = oldptr[idx];
free(oldptr);
theArray->shm_array = shm_array;
调用移至对shm*
执行[非共享] malloc
的低级函数中,因此您可以省去多余的复制操作。
(4)在您的fork例程中,您正在调用:
shm_array
您要在int partitionIndex = partition(arr, low, high);
之后进行此操作,因此, 父母和fork
的孩子都试图进行分区操作,因此会产生冲突。
因此,rpid
首先需要:
quickSortFork
(5)您正在创建 way 进程,并且由于进程插槽不可用,if (low < high) {
int partitionIndex = partition(arr, low, high);
rpid = fork();
调用开始失败。
这可能是程序似乎挂起的原因。
使用少量数组元素可能无法观察到,但是如果数组足够大(例如100,000个元素),则会发生这种情况
这是一个有效的版本[带有一些额外的调试代码]。
为解决最后的fork
问题,我创建了一个fork
,它不使用<{>> 使用quickSortStd
,而是调用了该名称。
处理过多fork
调用问题的一种方法是让fork
跟踪递归深度,并在深度足够高后调用非fork版本。
通常,在一定数量后添加更多进程/线程会适得其反,因为在进程之间进行切换的开销使并行性的优势黯然失色。这是一个调整选项。
我在quickSortFork
中添加了一个简单的想法,它似乎可行,因此请调整深度限制以适合您的需求。
quickSortFork
答案 1 :(得分:0)
一个直接的问题是
void quickSortFork(MyArray *arr, int low, int high){
pid_t lpid, rpid;
rpid = fork();
if(low < high){
int partitionIndex = partition(arr,low, high);
父母和孩子都开始划分相同的范围,显然是互相踩脚趾。
让父级进行分区,然后再进行分叉。