Чтение элемент за элементом работает, но чтение фрагмента не будет - PullRequest
0 голосов
/ 13 ноября 2018

Я пытаюсь определить, существует ли элемент в векторе, используя N процессов, и если true, вернуть все его позиции. Каждый процесс получает индекс и шаг. Индекс имеет значение от 0 до «numberOFProcesses -1», и каждый элемент проверки процесса, начиная с индекса, увеличивается с шагом.

Как это работает: Предположим, у нас есть 4 процесса. Процесс 0 проверяет элементы 0,4,8 ..., процесс 1 проверяет 1,5,9 ... и т. Д.

Как я это реализовал: Я получил 2 трубы: одна труба используется для позиций; второй канал для хранения количества вхождений цели. Всякий раз, когда процесс находит цель, он увеличивает число вхождений и записывает индекс в канал " index " и, наконец, после выхода из задания он записывает в " вхождения " канал количество вхождений, если таковые имеются, и возвращают истину или ложь. Первоначально я хотел напрямую вернуть количество вхождений, но понял, что «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

1 Ответ

0 голосов
/ 13 ноября 2018
...
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 - это сумма от всех процессов. Я думаю, что вы хотели:

int *indexes = (int *)malloc(sizeof(int) * totalOccurences);
read(index_pipe[READ], indexes, sizeof(int) * totalOccurences);
  1. Мне нравится эта идея параллелизма и отдельных каналов для связи с несколькими процессами. Вы можете немного ускорить процесс, используя realloc + read(index_pipe[READ], ..., sizeof(int) * occurences) прямо в цикле чтения if (exit_status == TRUE). Таким образом, вы могли ранее освободить данные, буферизованные в pipe.
  2. Я не думаю, что есть необходимость в occurences_pipe, если вас просто интересует сумма всех вхождений. Вы можете просто установить O_NONBLOCK на index_pipe[READ] и читать из него побайтно (или чанком по чанку), пока все потоки не завершат , а чтение вернет 0. Сумма всех вхождений - это число байтов, прочитанных из index_pipe после завершения всех потоков, разделенных на sizeof(int).
  3. Я думаю, что потоки лучше подходят для такой задачи, вы копируете весь массив между процессами на fork, когда при использовании pthreads каждый поток использует одну и ту же память.
  4. И, ради любви к K & R, не использует результат malloc .
...