我正在尝试使用N个进程确定元素是否在向量中退出,如果为true,则返回其所有位置。每个过程都接收一个索引和一个步骤。索引从0到“ numberOFProcesses -1”,并且每个进程检查元素都从索引开始,并逐步增加。
工作原理:让我们假设我们有4个流程。流程0检查元素0,4,8 ...,流程1检查元素1,5,9 ...等等。
我是如何实现的:我有2个管道:一个用于位置;第二个管道用于存储目标的出现次数。每当进程找到目标时,它都会增加出现的次数,并将索引写到“ 索引”管道中,最后,在退出作业时,它会写入“ 出现次数”传递出现的次数(如果有),并返回true或false。我最初想直接返回出现的次数,但我意识到“ WEXITSTATUS”仅使用8位,这可能是个问题。
问题:尝试读取大小为“出现次数”的块失败或给出无效结果。一次读取一个值似乎很好。我也使用valgrind和gdb检查了它,但似乎找不到问题。 Valgrind在尝试读取块时报告大量问题,但一次读取一个时报告0个错误。只有在流程找到目标后,才读取事件。
P.S。我知道我可以这样离开,但多次阅读毫无意义。
现在,输入一些代码:
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <sys/signal.h>
#include <sys/types.h>
/**
* @brief basic defines
*
*/
#define MAX_RAND 100
#define TRUE 1
#define FALSE 0
#define CHILDREN 0
#define READ 0
#define WRITE 1
int size = 13;
int *array;
int target;
int index_pipe[2];
int occurences_pipe[2];
/**
* @brief this populates the array with random number
*
* @param array the given array
* @param size the size of the array
*/
void populate(int *array, int size)
{
for (int i = 0; i < size; i++)
{
array[i] = rand() % MAX_RAND;
}
}
/**
* @brief this determines whether an elements occurs in an array and writes to pipes the number
* of occurences and the the indexes on which resides the target
*
* @param target the value we are looking for
* @param index the index of the process, i.e. the process id
* @param step the step, i.e. the number of processes
* @return int the search status. This returns true if "target occurs", FALSE otherwise
*/
int search(int target, int index, int step)
{
int i = index;
int numberOfOccurences = 0;
/**
* @brief each process will start at position index and will check values starting with index, incrementing with step
* ex: process 0 will check 0,4,8,12..
* process 1 will check 1,5,9,13...
*/
while (i < size)
{
if (target == array[i])
{
/**
* @brief if the target occues increment the number of occurences and write an index to pipe
*
*/
numberOfOccurences++;
write(index_pipe[WRITE], &i, sizeof(int));
}
i += step;
}
/**
* @brief write occurences to pipe if, and only if, the number of occurences is not 0,
* i.e. we have found the target at least once and return TRUE or FALSE
*
*/
if (numberOfOccurences != 0)
{
write(occurences_pipe[WRITE], &numberOfOccurences, sizeof(int));
return TRUE;
}
return FALSE;
}
/**
* @brief this prints a given array
*
* @param array the array we want to print
* @param size the size of the array
*/
void printArray(int *array, int size)
{
printf("Array: \n");
for (int i = 0; i < size; i++)
{
printf("%d ", array[i]);
}
printf("\n");
}
/**
* @brief entry point
*
* @return int EXIT_SUCCESS
*/
int main()
{
/**
* @brief initialize and allocate memory
*
*/
size = 13;
array = (int *)malloc(sizeof(int) * size);
pipe(index_pipe);
pipe(occurences_pipe);
int numerOfProccesses = 3;
int target = 15;
int totalOccurences = 0;
int status = -1;
int exit_status = -1;
int occurences = -1;
populate(array, size);
array[size - 1] = target;
printArray(array, size);
size_t processes[numerOfProccesses];
/**
* @brief create childrens and put them to work
*
*/
for (int i = 0; i < numerOfProccesses; i++)
{
processes[i] = fork();
if (CHILDREN == processes[i])
{
/**
* @brief get the search status and exit
*
*/
int exit_status = search(target, i, numerOfProccesses);
exit(exit_status);
}
}
/**
* @brief wait for children to exit
*
*/
for (int i = 0; i < numerOfProccesses; i++)
{
/**
* @brief wait for each children. If a children is done AND it has found taget, i.e. returned TRUE,
* then read the number of occurrences from pipe
*
*/
wait(&status);
if (WIFEXITED(status))
{
exit_status = WEXITSTATUS(status);
if (exit_status == TRUE)
{
read(occurences_pipe[READ], &occurences, sizeof(int));
totalOccurences += occurences;
}
}
}
/**
* @brief if the number of occurrences is 0, then we have'nt found target
*
*/
if (totalOccurences == 0)
{
printf("%d not found \n", target);
}
else
{
/**
* @brief else allocate memory for an array of size "occurrences" and read from index pipe
*
*/
printf("Found %d on %d positions\n", target, totalOccurences);
int *indexes = (int *)malloc(sizeof(int) * 3);
// for (int i = 0; i < totalOccurences; i++)
// {
// int value;
// read(index_pipe[READ], &value, sizeof(int));
// printf("Read %d \n", value);
// }
int pipe_status;
pipe_status = read(index_pipe[READ], indexes, totalOccurences);
printf("Pipe read %d bytes\n", pipe_status);
printArray(indexes, totalOccurences);
}
return 0;
}
预期输出:
Array:
83 86 77 15 93 35 86 92 49 21 62 27 15
Found 15 on 2 positions
Read 3
Read 12
Array:
3 12
我在一次读取一个块时得到了这个信息:
Array:
83 86 77 15 93 35 86 92 49 21 62 27 15
Found 15 on 2 positions
Pipe read 2 bytes
Array:
3 0
P.S。我是在Linux机器上写的。我使用以下代码进行了编译:gcc -g -o search search.c -Wextra
答案 0 :(得分:1)
...
read(occurences_pipe[READ], &occurences, sizeof(int));
totalOccurences += occurences;
int *indexes = (int *)malloc(sizeof(int) * 3);
read(index_pipe[READ], indexes, totalOccurences);
好吧,您正在读取未知数量的字节,这是从管道中每个进程中发现的数字的总和,并将其保存到sizeof(int) * 3
个字节中,这很可能会溢出。 totalOccurences
也是所有进程的 sum 。我想你的意思是:
int *indexes = (int *)malloc(sizeof(int) * totalOccurences);
read(index_pipe[READ], indexes, sizeof(int) * totalOccurences);
read(index_pipe[READ], ..., sizeof(int) * occurences)
循环中使用realloc + if (exit_status == TRUE)
来加快处理速度。这样,您可以更早地释放管道中缓冲的数据。index_pipe[READ]
上设置O_NONBLOCK,然后逐字节(或逐块)读取它,直到所有线程完成并且都将返回0。所有事件的总和是所有线程退出后从index_pipe读取的字节数除以sizeof(int)
。