Почему я продолжаю получать ошибки сегментации в моей C-программе - PullRequest
1 голос
/ 20 марта 2019

Я пытался реализовать синхронизацию потоков на C. Однако я продолжаю получать ошибку сегментации, когда я вызываю функцию, которую я хочу, чтобы поток выполнял. Кто-нибудь может предложить решение этой проблемы?

Вот мой код

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>

#define N 5
#define M 3
#define LEFT (robot_id - 1) % N
#define RIGHT (robot_id + 1) % N

pthread_t robots_id[N];
sem_t simulations[M];
pthread_mutex_t sever_mutex;

void Learning(int robot_id)
{
    printf("learning robot = %d\n", robot_id);
}

void *robotAct(void *id)
{
    int *robot_id = id;
    printf("robot id = %d\n", robot_id);
    Learning(*robot_id);
}

int main(int argc, char *argv[])
{
    int E, T;

    E = atoi(argv[1]);
    T = atoi(argv[2]);

    printf("Initializing Robot!\n");

    //Initializes the simulations
    for (int i = 0; i < M; i++)
    {
        sem_init(&simulations[i], 0, 0);
    }

    //Initializes the robots
    for (int i = 0; i < N; i++)
    {
        printf("Robot %d is created\n", i + 1);
        pthread_create(&robots_id[i], NULL, robotAct, (void *)i + 1);
    }

    sleep(T);

    printf("Terminating Robots\n");
    for (int i = 0; i < N; i++)
    {
        pthread_cancel(robots_id[i]);
    }
    printf("Termination is completed!\n");
    printf("-------Report-------------\n");
    //getReport();
    return 0;
}

Вот мой результат, который я продолжаю получать

Initializing Robot!
Robot 1 is created
Robot 2 is created
Robot 3 is created
robot id = 1
robot id = 2
Robot 4 is created
robot id = 3
[1]    54477 segmentation fault  ./project 5 10

1 Ответ

1 голос
/ 20 марта 2019

Основная проблема объясняется в моем комментарии:

Вы не передаете действительный указатель на функцию потока. В большинстве случаев вы почти сошли с рук от неправильного использования этого в вызове printf() в robotAct(); вам категорически не сходит с рук при вызове Learning(), где вы разыменовываете недействительный не указатель.

Решение заключается в создании массива целых чисел в основной программе, который содержит идентификационные номера роботов (int id[N];). Затем инициализируйте каждый элемент и передайте &id[i] в pthread_create().

Не следует печатать адреса в формате %d (даже если он работает в 32-разрядных системах; он не работает в 64-разрядных системах). Правильный метод - использовать %p для форматирования адреса. Или, в этом случае, выведите целое число, а не адрес, используя *robot_id.

Следующий код имеет минимальную адаптацию к исходному коду и не был скомпилирован или протестирован (могут быть проблемы за пределами измененных строк):

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>

#define N 5
#define M 3
#define LEFT (robot_id - 1) % N
#define RIGHT (robot_id + 1) % N

pthread_t robots_id[N];
sem_t simulations[M];
pthread_mutex_t sever_mutex;

void Learning(int robot_id)
{
    printf("learning robot = %d\n", robot_id);
}

void *robotAct(void *id)
{
    int *robot_id = id;
    printf("robot id = %d\n", *robot_id);        // Changed
    Learning(*robot_id);
    return 0;                                    // Added
}

int main(int argc, char *argv[])
{
    int E, T;
    int id[N];                                   // Added

    E = atoi(argv[1]);
    T = atoi(argv[2]);

    printf("Initializing Robot!\n");

    //Initializes the simulations
    for (int i = 0; i < M; i++)
    {
        sem_init(&simulations[i], 0, 0);
    }

    //Initializes the robots
    for (int i = 0; i < N; i++)
    {
        printf("Robot %d is created\n", i + 1);
        id[i] = i + 1;                                          // Added
        pthread_create(&robots_id[i], NULL, robotAct, &id[i]);  // Changed
    }

    sleep(T);

    printf("Terminating Robots\n");
    for (int i = 0; i < N; i++)
    {
        pthread_cancel(robots_id[i]);
    }
    printf("Termination is completed!\n");
    printf("-------Report-------------\n");
    //getReport();
    return 0;
}

Избегайте использования pthread_cancel() для завершения потоков; потоки должны заканчиваться под контролем. Например, в главном потоке может быть установлен флаг, указывающий, что потоки должны прекратиться, и они будут периодически это проверять. Обычно pthread_join() используется для очистки завершенных потоков.

Для будущих публикаций, пожалуйста, прочитайте о том, как создать MCVE ( Минимальный, Полный, Проверяемый Пример ). Приведенные части кода не имеют отношения к проблеме - мьютекс и семафоры, например, на самом деле не используются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...