Я играю с решением проблемы обедающих философов с использованием мьютексов, однако программа segfaulting, вероятно, связана с ошибкой, связанной с потоком. То, что я пытаюсь сделать здесь, это в основном думать о форке как о мьютексе и создать функцию void *eat(void *arg)
, а затем закрыть критическую секцию (критическая секция - это просто поток, объявляющий свой идентификатор и который в настоящее время ест), независимо от того, какая функция вызывается, затем я перебираю все мои философы и проверяю, делится ли его идентификатор (идентификатор начинается с 0) на 2.
В первом раунде едят только идентификаторы потоков, которые делятся на 2, а во втором раунде едят только идентификаторы потоков, которые не делятся, и так далее в бесконечном цикле.
Я знаю, что это до глупости простое решение, которое, вероятно, не решает проблему. в первую очередь. так что, пожалуйста, потерпите меня. если у вас есть какие-либо вопросы, пожалуйста, дайте мне знать в комментарии.
struct typedef t_philo
{
pthread_t thread;
pthread_mutex_t fork;
int id;
}
t_philo;
void *eat(void *arg)
{
t_philo *philo = (t_philo *)arg;
pthread_mutex_lock(&philo->fork);
printf("philo with id: %i is eating\n", philo->id);
pthread_mutex_unlock(&philo->fork);
return (NULL);
}
void first_round(t_philo *philo, int len)
{
for (int i = 0; i < len; i++)
if (!(i % 2))
pthread_join(philo[i].thread, NULL);
}
void second_round(t_philo *philo, int len)
{
for (int i = 0; i < len; i++)
if ((i % 2))
pthread_join(philo[i].thread, NULL);
}
int main(int argc, char **argv)
{
t_philo *philo;
// how many philosophers is given as first arg.
int len = atoi(argv[1]);
if (argc < 2)
exit(EXIT_FAILURE);
philo = malloc(sizeof(*philo) * atoi(argv[1]));
//this function add id's and initialize some data.
init_data(philo, argv);
for (int i = 0; i < len; i++)
pthread_create(&philo[i].thread, NULL, eat(&philo[i]), &philo[i]);
while (1)
{
first_round(philo, len);
second_round(philo, len);
}
return 0;
}
ВЫХОД
philo with id: 0 is eating
philo with id: 1 is eating
philo with id: 2 is eating
philo with id: 3 is eating
philo with id: 4 is eating
.
.
.
.
philo with id random is eating
[1] 29903 segmentation fault
Вывод каждый раз достигает случайного идентификатора и segfault, поэтому я пришел к выводу, что это может быть ошибка потока.
В main
int len = argv[1];
неправильно. Если вы скомпилировали с включенными предупреждениями (например, -Wall
), этот оператор будет помечен компилятором.
Как бы то ни было, вы получаете значение огромный для len
. Итак, позже цикл for
переполнит выделенный вами массив, и у вас будет UB.
Вы, вероятно, хотите: int len = atoi(argv[1]);
как у вас для malloc
.
И вы хотите сделать эту после проверку argc
.
И зачем вызывать atoi
дважды [с исправлением]?
Вот рефакторинг кода:
int
main(int argc, char **argv)
{
t_philo *philo;
if (argc < 2)
exit(EXIT_FAILURE);
// how many philosophers is given as first arg.
int len = atoi(argv[1]);
philo = malloc(sizeof(*philo) * len);
// do stuff ...
return 0;
}
Пожалуйста, редактировать ваш вопрос и добавьте минимальную версию, которая компилирует чисто и может вызвать проблему
pthread_create
имеет следующий прототип:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
start_routine
это указатель функции. Однако вы звоните pthread_create
с помощью неверные аргументы: eat(&philo[i])
. Таким образом, программа вызывает eat
правильно, а затем пытается звоните NULL
(из нового потока), потому что это значение, возвращаемое eat
. Случайность возникает из-за переменного времени, необходимого для фактического создания потоков.
Обратите внимание, что с помощью отладчика должен помочь вам очень легко найти и устранить проблему. Отладчики, такие как gdb, немного сложны в освоении, но как только это сделано, такие ошибки, как segfault, становится почти легко исправить. Я также удивлен, что такой компилятор, как clang, не заметит проблемы с набором текста во время компиляции.
Да, пропустил это, мне нужно пересмотреть свои основы, спасибо. если у вас есть хорошие ресурсы для изучения отладчика, пожалуйста, облегчите.
Существуют документы/веб-сайты, такие как Вот этот или Вот этот, но большинство из них не очень удобны для пользователя. Я лично узнал на работе (в течение нескольких лет). При этом я думаю, что в этом случае не должно быть слишком сложно использовать gdb для поиска ошибки: достаточно просто скомпилировать с помощью -g
, запустить программу с помощью gdb и просмотреть стек. Обратите внимание, что gdb имеет очень полезный режим --tui
для графического интерфейса на основе консоли.
извините, это не проблема, я просто минимизировал свою программу для простоты, в моей длинной версии я фактически преобразовываю длину и другие 3 параметра в целые числа и сохраняю их более или менее эффективным способом, это всего лишь короткая версия программа, которая проливает свет на логику, которая имеет значение, проблема связана с ошибкой, программа работает и segfaulting случайным образом с разными идентификаторами. Я исправлю ошибку, извините за введение в заблуждение.