Обработка файла с несколькими процессами и потоками - PullRequest
0 голосов
/ 24 апреля 2018

У меня проблемы с этим упражнением синхронизации между процессами и потоками. Основной процесс должен создавать N дочерних элементов (заставляя их запускаться примерно в одно и то же время), что, в свою очередь, должно создавать M потоков. Теперь эти темы должны писать в файл. Через некоторое время T основной поток должен остановить дочерние процессы и вызвать функцию, которая найдет, какой процесс сделал больше обращений. Не должно быть важно, что будет написано в файле или как основной процесс решит, какой из них будет написан больше. Проблема в том, что ничего не написано. Файл создан, но ничего не происходит, и я не могу понять, почему. Я потратил впустую день на это, и я до сих пор не могу понять, что не так (хотя я подозреваю, что sigaction, так как я не ожидал использовать это, чтобы остановить дочерние процессы). Пожалуйста помоги. Вот код

РЕДАКТИРОВАТЬ: проблема не должна быть в init_file () или parseOutput () , так как они были предоставлены мне профессором, проверены, и я оставил их без изменений

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <semaphore.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <signal.h>

// macros for error handling
#include "common.h"

#define N 10   // child process count
#define M 10   // thread per child process count
#define T 3     // time to sleep for main process

#define FILENAME    "accesses.log"
#define SEMFILENAME "/sem_file"
#define SEMPROCESSESNAME "/sem_proc"

/*
 * data structure required by threads
 */
typedef struct thread_args_s {
    unsigned int child_id;
    unsigned int thread_id;
} thread_args_t;

/*
 * parameters can be set also via command-line arguments
 */
int n = N, m = M, t = T;

/* TODO: declare as many semaphores as needed to implement
 * the intended semantics, and choose unique identifiers for
 * them (e.g., "/mysem_critical_section") */
sem_t * sem_file;
sem_t * sem_processes;
int running = 1;

/*
 * Create a named semaphore with a given name, mode and initial value.
 * Also, tries to remove any pre-existing semaphore with the same name.
 */
sem_t *create_named_semaphore(const char *name, mode_t mode, unsigned int value) {
    printf("[Main] Creating named semaphore %s...", name);
    fflush(stdout);

    // TODO
    sem_unlink(name);
    sem_t *ret;
    ret = sem_open(name, O_CREAT, mode, value);

    if(ret == SEM_FAILED)
        {
            fprintf(stderr, "failed to open %s", name);
            exit(EXIT_FAILURE);
        }
    printf("done!!!\n");
    return ret;
}

/*
 * Ensures that an empty file with given name exists.
 */
void init_file(const char *filename) {
    printf("[Main] Initializing file %s...", filename);
    fflush(stdout);
    int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
    if (fd<0) handle_error("error while initializing file");
    close(fd);
    printf("closed...file correctly initialized!!!\n");

    sem_file = create_named_semaphore(SEMFILENAME, 0777, 1);
}
/*
 * Child's signal handler
 */
void child_sig_handler(int signum) {
    running = 0;
}


void parseOutput() {
    // identify the child that accessed the file most times
    int* access_stats = calloc(n, sizeof(int)); // initialized with zeros
    printf("[Main] Opening file %s in read-only mode...", FILENAME);
    fflush(stdout);
    int fd = open(FILENAME, O_RDONLY);
    if (fd < 0) handle_error("error while opening output file");
    printf("ok, reading it and updating access stats...");
    fflush(stdout);

    size_t read_bytes;
    int index;
    do {
        read_bytes = read(fd, &index, sizeof(int));
        if (read_bytes > 0)
            access_stats[index]++;
    } while(read_bytes > 0);
    printf("ok, closing it...");
    fflush(stdout);

    close(fd);
    printf("closed!!!\n");

    int max_child_id = -1, max_accesses = -1, i;
    for (i = 0; i < n; i++) {
        printf("[Main] Child %d accessed file %s %d times\n", i, FILENAME, access_stats[i]);
        if (access_stats[i] > max_accesses) {
            max_accesses = access_stats[i];
            max_child_id = i;
        }
    }
    printf("[Main] ===> The process that accessed the file most often is %d (%d accesses)\n", max_child_id, max_accesses);
    free(access_stats);
}

void* thread_function(void* x) {
    thread_args_t *args = (thread_args_t*)x;

    /* TODO: protect the critical section using semaphore(s) as needed */
    if(sem_wait(sem_file)) handle_error("failed to wait on sem_file");
    // open file, write child identity and close file

    int fd = open(FILENAME, O_WRONLY | O_APPEND);
    if (fd < 0) handle_error("error while opening file");

    printf("[Child#%d-Thread#%d] File %s opened in append mode!!!\n", args->child_id, args->thread_id, FILENAME);   

    write(fd, &(args->child_id), sizeof(int));
    printf("[Child#%d-Thread#%d] %d appended to file %s opened in append mode!!!\n", args->child_id, args->thread_id, args->child_id, FILENAME);    
    close(fd);

    if(sem_post(sem_file)) handle_error("failed to release sem_file");

    printf("[Child#%d-Thread#%d] File %s closed!!!\n", args->child_id, args->thread_id, FILENAME);


    pthread_exit(NULL);
}

void childProcess(int child_id) {
    /* TODO: each child process notifies the main process that it
     * is ready, then waits to be notified from the main in order
     * to start. As long as the main process does not notify a
     * termination event [hint: use sem_getvalue() here], the child
     * process repeatedly creates m threads that execute function
     * thread_function() and waits for their completion. When a
     * notification has arrived, the child process notifies the main
     * process that it is about to terminate, and releases any
     * shared resources before exiting. */
    sem_wait(sem_processes);

    int i;
    pthread_t threads[M];
    while(running)
    {
        for(i = 0; i < M; i++)
            if(pthread_create(threads+i, NULL, &thread_function, NULL)) handle_error("Failed to create pthread");
        for(; i > 0; i ++)
            if(pthread_join(threads[i], NULL)) handle_error("Failed to join pthread");
    }
    _exit(EXIT_SUCCESS);
}

void mainProcess() {
    /* TODO: the main process waits for all the children to start,
     * it notifies them to start their activities, and sleeps
     * for some time t. Once it wakes up, it notifies the children
     * to end their activities, and waits for their termination.
     * Finally, it calls the parseOutput() method and releases
     * any shared resources. */
    int i;
    unsigned t_left = T;
    pid_t id, *childs_ids = malloc(sizeof(pid_t)*N);

    sem_processes = create_named_semaphore(SEMPROCESSESNAME, 0777, 0);

    struct sigaction act;
    memset(&act, 0, sizeof(act));
    act.sa_handler = &child_sig_handler;
    sigaction(SIGTERM, &act, NULL);

    for(i = 0; i < N; i++)
    {
        id = fork();
        if(id < 0)
            handle_error("Fork failed");
        if(id == 0)
            childProcess(i);
        childs_ids[i] = id;
    }
    for(; i > 0; i--)
        sem_post(sem_processes);

    //Sleeps for T seconds
    while((t_left = sleep(t_left)));

    for(; i < N; i++)
        {
            kill(childs_ids[i], SIGTERM);
        }

    int status;
    for(; i>0; i--)
        if(wait(&status)< 0) handle_error("wait failed");
    parseOutput();
}

int main(int argc, char **argv) {
    // arguments
    if (argc > 1) n = atoi(argv[1]);
    if (argc > 2) m = atoi(argv[2]);
    if (argc > 3) t = atoi(argv[3]);

    // initialize the file
    init_file(FILENAME);

    /* TODO: initialize any semaphore needed in the implementation, and
     * create N children where the i-th child calls childProcess(i); then
     * the main process executes function mainProcess() once all the
     * children have been created */
    mainProcess();

    if(sem_close(sem_processes)) handle_error("failed to close sem_processes");
    if(sem_close(sem_file)) handle_error("failed to close sem_file");
    if(sem_unlink(SEMPROCESSESNAME)) handle_error("failed to unlink sem_processes");
    if(sem_unlink(SEMFILENAME)) handle_error("failed to unlink sem_file");
    exit(EXIT_SUCCESS);
}

А вот вывод на оболочку:

[Main] Child 0 accessed file accesses.log 0 times
[Main] Child 1 accessed file accesses.log 0 times
[Main] Child 2 accessed file accesses.log 0 times
[Main] Child 3 accessed file accesses.log 0 times
[Main] Child 4 accessed file accesses.log 0 times
[Main] Child 5 accessed file accesses.log 0 times
[Main] Child 6 accessed file accesses.log 0 times
[Main] Child 7 accessed file accesses.log 0 times
[Main] Child 8 accessed file accesses.log 0 times
[Main] Child 9 accessed file accesses.log 0 times
[Main] Child 10 accessed file accesses.log 0 times
[Main] Child 11 accessed file accesses.log 0 times
[Main] Child 12 accessed file accesses.log 0 times
[Main] Child 13 accessed file accesses.log 0 times
[Main] Child 14 accessed file accesses.log 0 times
[Main] Child 15 accessed file accesses.log 0 times
[Main] Child 16 accessed file accesses.log 0 times
[Main] Child 17 accessed file accesses.log 0 times
[Main] Child 18 accessed file accesses.log 0 times
[Main] Child 19 accessed file accesses.log 0 times
[Main] Child 20 accessed file accesses.log 0 times
[Main] Child 21 accessed file accesses.log 0 times
[Main] Child 22 accessed file accesses.log 0 times
[Main] Child 23 accessed file accesses.log 0 times
[Main] Child 24 accessed file accesses.log 0 times
[Main] Child 25 accessed file accesses.log 0 times
[Main] Child 26 accessed file accesses.log 0 times
[Main] Child 27 accessed file accesses.log 0 times
[Main] Child 28 accessed file accesses.log 0 times
[Main] Child 29 accessed file accesses.log 0 times
[Main] Child 30 accessed file accesses.log 0 times
[Main] Child 31 accessed file accesses.log 0 times
[Main] Child 32 accessed file accesses.log 0 times
[Main] Child 33 accessed file accesses.log 0 times
[Main] Child 34 accessed file accesses.log 0 times
[Main] Child 35 accessed file accesses.log 0 times
[Main] Child 36 accessed file accesses.log 0 times
[Main] Child 37 accessed file accesses.log 0 times
[Main] Child 38 accessed file accesses.log 0 times
[Main] Child 39 accessed file accesses.log 0 times
[Main] Child 40 accessed file accesses.log 0 times
[Main] Child 41 accessed file accesses.log 0 times
[Main] Child 42 accessed file accesses.log 0 times
[Main] Child 43 accessed file accesses.log 0 times
[Main] Child 44 accessed file accesses.log 0 times
[Main] Child 45 accessed file accesses.log 0 times
[Main] Child 46 accessed file accesses.log 0 times
[Main] Child 47 accessed file accesses.log 0 times
[Main] Child 48 accessed file accesses.log 0 times
[Main] Child 49 accessed file accesses.log 0 times
[Main] Child 50 accessed file accesses.log 0 times
[Main] Child 51 accessed file accesses.log 0 times
[Main] Child 52 accessed file accesses.log 0 times
[Main] Child 53 accessed file accesses.log 0 times
[Main] Child 54 accessed file accesses.log 0 times
[Main] Child 55 accessed file accesses.log 0 times
[Main] Child 56 accessed file accesses.log 0 times
[Main] Child 57 accessed file accesses.log 0 times
[Main] Child 58 accessed file accesses.log 0 times
[Main] Child 59 accessed file accesses.log 0 times
[Main] Child 60 accessed file accesses.log 0 times
[Main] Child 61 accessed file accesses.log 0 times
[Main] Child 62 accessed file accesses.log 0 times
[Main] Child 63 accessed file accesses.log 0 times
[Main] Child 64 accessed file accesses.log 0 times
[Main] Child 65 accessed file accesses.log 0 times
[Main] Child 66 accessed file accesses.log 0 times
[Main] Child 67 accessed file accesses.log 0 times
[Main] Child 68 accessed file accesses.log 0 times
[Main] Child 69 accessed file accesses.log 0 times
[Main] Child 70 accessed file accesses.log 0 times
[Main] Child 71 accessed file accesses.log 0 times
[Main] Child 72 accessed file accesses.log 0 times
[Main] Child 73 accessed file accesses.log 0 times
[Main] Child 74 accessed file accesses.log 0 times
[Main] Child 75 accessed file accesses.log 0 times
[Main] Child 76 accessed file accesses.log 0 times
[Main] Child 77 accessed file accesses.log 0 times
[Main] Child 78 accessed file accesses.log 0 times
[Main] Child 79 accessed file accesses.log 0 times
[Main] Child 80 accessed file accesses.log 0 times
[Main] Child 81 accessed file accesses.log 0 times
[Main] Child 82 accessed file accesses.log 0 times
[Main] Child 83 accessed file accesses.log 0 times
[Main] Child 84 accessed file accesses.log 0 times
[Main] Child 85 accessed file accesses.log 0 times
[Main] Child 86 accessed file accesses.log 0 times
[Main] Child 87 accessed file accesses.log 0 times
[Main] Child 88 accessed file accesses.log 0 times
[Main] Child 89 accessed file accesses.log 0 times
[Main] Child 90 accessed file accesses.log 0 times
[Main] Child 91 accessed file accesses.log 0 times
[Main] Child 92 accessed file accesses.log 0 times
[Main] Child 93 accessed file accesses.log 0 times
[Main] Child 94 accessed file accesses.log 0 times
[Main] Child 95 accessed file accesses.log 0 times
[Main] Child 96 accessed file accesses.log 0 times
[Main] Child 97 accessed file accesses.log 0 times
[Main] Child 98 accessed file accesses.log 0 times
[Main] Child 99 accessed file accesses.log 0 times
[Main] ===> The process that accessed the file most often is 0 (0 accesses)

Также здесь часто встречаются.

#include <errno.h>

#include <stdio.h>

#include <string.h>



// macros for handling errors

#define handle_error_en(en, msg)    do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

#define handle_error(msg)           do { perror(msg); exit(EXIT_FAILURE); } while (0)

1 Ответ

0 голосов
/ 11 мая 2018

Функция потока нуждалась в аргументе типа thread_args_t, и я передавал NULL. Я даже не знаю, почему это никогда не вызывало ошибки сегментации. При правильном вводе pthread_create все работает нормально.

...