LINUX.ORG.RU

Азы работа с потоками (си, линукс) и «Ошибка сегментирования (сделан дамп памяти)»

 , ,


0

1

Есть такой код:

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>

void * thread_func( char arg[])
{
	printf("%s", arg);
}

int main()
{
	int id;
	pthread_t thread1;
	printf("\n--- start first thread--\n");
	pthread_create(&thread1, NULL, thread_func("1"), &id);
	printf("\n--- end of start first thread--\n");
	printf("\n--- start second thread--\n");
	pthread_create(&thread1, NULL, thread_func("2"), &id);
	printf("\n--- end of start second thread--\n");
printf("Done\n");
}
Компилирую его с опцией "-pthread" При запуске бинарника 1 раз из 10ти программа отрабатывает от начала и до конца, а в 9ти - вываливается в РАЗНЫХ местах с ошибкой:
Ошибка сегментирования (сделан дамп памяти)
Подозреваю, что где-то либо пропустил какую-то мелочь, либо типы где-то не соответствуют шаблонам, но не могу найти где и чего напутал... Пример был взят где-то в инете и переделан (много чего было выкинуто)...

Конкретно в приведеном коде где(какая) ошибка?


thread_func(«1»)

man pthreat_create

Третьим аргументом должен быть указатель на функцию. То есть, в твоём случае просто «thread_func», а уже четвёртым аргументом должен быть твой аргумент, имеющий тип void*, который в самой функции кастанёшь к тому указателю, который нужно.

Deleted
()

К тому же, здесь всё очень плохо. У тебя надпись «end of start first thread» появится раньше, чем сам поток закончится. Подумай, почему.

Deleted
()
Ответ на: комментарий от Deleted

по поводу параметров - спс, то что нужно! по поводу надписей - все норм, это «скелет» для понимания синтакиса/прочь. А в программе у меня так и планируется: во внутреннем цикле main будут стартовать нити, в которых будет собственный цикл ожидания собития... потому порядок вывода строк мне не важен, абы стартовало и не сыпалось хоть в этом... )))

Спасибо за быстрый и исчерпывающий ответ, тема исчерпана)

nk_lg
() автор топика

помимо сказанного в main(),thread_func() нехватает return`ов.

компиль с ключами -Wall -Wextra, компилятор сам подскажет про такие «детские» ошибки.

MKuznetsov ★★★★★
()

О как. Новички уже даже не удосуживаются посмотреть какие параметры функция принимает. Так копируют. А еще в сишку лезут. Понарожают ...

anonymous
()
Ответ на: комментарий от xaizek

5.1.2.2.3

Program termination

1) If the return type of the main function is a type compatible with int , a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument; 11) reaching the } that terminates the main function returns a value of 0. If the return type is not compatible with int , the termination status returned to the host environment is unspecified.

Так что вернуть может все что угодно, в данном конкретно случае скорее всего main вернет результат вызова printf(«Done\n»).

NegatiV
()
Ответ на: комментарий от MKuznetsov
-Wall -Wextra

Спасибо! Многое стало «прозрачнее»!

nk_lg
() автор топика
Ответ на: комментарий от Gvidon

Ага, я только сейчас заметил что не по теме ответил.

NegatiV
()
Ответ на: комментарий от DELIRIUM

Не только. Тут цитата из стандарта C99. В C90 возвращается undefined значение, но даже не знаю, на сколько имеет смысл ориентироваться на него в 2014 году.

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

на сколько имеет смысл ориентироваться на него

Надо всегда возвращать значение из main(), как из любой другой функции, и не извращаться. Если, конечно, на извращения нет веских причин.

Sorcerer ★★★★★
()

А зачем тебе потоки вообще? Ты собрался километры данных туда-сюда возить? fork кстати вообще никаких данных не принимает.

nanoolinux ★★★★
()
Ответ на: комментарий от Sorcerer

Надо всегда возвращать значение из main(), как из любой другой функции, и не извращаться. Если, конечно, на извращения нет веских причин.

Согласен, причём стараюсь использовать EXIT_SUCCESS/EXIT_FAILURE. Я имел в виду ориентироваться в суждениях о языке, какую версию стандарта подразумевать по умолчанию. Ну и изначально просто указывал на то, что это не «ошибка», а не ратовал писать таким образом.

xaizek ★★★★★
()
Ответ на: комментарий от invy

«Вы, вероятно, обратили внимание на инструкцию return в конце main. Поскольку main есть функция, как и любая другая, она может вернуть результирующее значение тому, кто ее вызвал, фактически в ту среду, из которой была запущена программа. Обычно возвращается нулевое значение, что говорит о нормальном завершении выполнения. Ненулевое значение сигнализирует о необычном или ошибочном завершении. До сих пор ради простоты мы опускали return в main, но с этого момента будем задавать return как напоминание о том, что программы должны сообщать о состоянии своего завершения в операционную систему.» Керниган, 3е издание.

Каюсь - грешен, решил что «для простоты» не стану возвращать return у примитива - теперь буду «лепить» его везде, дабы не драконить столь широкие слои...

А зачем тебе потоки вообще? Ты собрался километры данных туда-сюда возить? fork кстати вообще никаких данных не принимает.

- Алгоритм, который пытаюсь реализовать на си: Слушаем определенный порт; при получении сообщения от «сервера» - запускаем поток, в котором парсим/выполняем необходимые действия, продолжая слушать в основном цикле, дабы ничего не упустить...

а де pthread_join?

- А зачем? В момем случае «нить» должна обработать входное значение и завершиться, при этом результат обработки мне малоинтересен, так как в ней (нити) есть достаточное кол-во собственных обработок исключений и прочь... Или я опять недочитался стандарты и использование «pthread_join» как и «return» является правилом хорошего тона??

Затык №1:

system("MyEnv=`iptables -L |grep B8:B4:2E:`");
не хочет отрабатывать, ругается:
sh: 1: export: --: bad variable name
При этом просто в консоли данная комманда без проблем отрабатывает (программу запускаю от рута, так что «прав» ей должно хватать...?!) Или как еще можно узнать результат выполнения `iptables -L |grep B8:B4:2E:`? Мне нужно реализовать:
if (`iptables -L |grep B8:B4:2E:` == NULL) then

Пытаюсь сделать через «костыль» с заполнением/чтением промежуточной переменной MyEnv:

system("MyEnv=");
system("MyEnv=`iptables -L |grep B8:B4:2E:`");
char *langPtr = getenv("MyEnv");
if (langPtr == NULL) then
Подскажите, как более «правильно» реализовать описанную проверку, либо что не так с описанной?

Затык №2: Согласно той же «библии» от Кернигана:

«Когда аргументом является имя массива, то функции передается значение, которое является адресом начала этого массива, и никакие элементы массива не копируются. С помощью индексирования относительно полученного значения функция может получить доступ к любому элементу массива.»

Проверил - так и есть, и что самое паршивое в моем случае - я успеваю получить новое значение буфера «из порта» до того, как функция в потоке успевает обработать предыдущее, таким образом - функция «теряет» предыдущее значение и как ни в чем не бывало работает с вновь полученым... Уверен, что данная проблема «стара как мир» и дабы не выдумывать свой велосипед с очередными костылями - прошу помощи: ткните, пожалуйста, носом в ссылку с описанием проблематики «как передать функции значение элементов массива, а не указатель на первый элемент этого массива?».

nk_lg
() автор топика
Ответ на: комментарий от nk_lg

«Затык №1» решен простой заменой `` на $():

system("MyEnv=$(iptables -L |grep B8:B4:2E:)");
Костыль-костылем, но ничего лучшего «быстро» не придумал. Предложения по оптимизации реализации и всея алгоритма в целом приветствуются! ))

«Затык №2» пока что сильно смущает, ибо даже попытка скопировать «входной параметр» во внутренюю переменную на старте потока, и дальнейшая работа с копией в наколенной сборке показала, что между стартом нитки, memset'om и копированием из приходящего arg[] во внутреннюю str[] - «основной цикл» успевает «услышать» новое значение для arg[], и все... Получается что нить уже работает с ним... Беда))

nk_lg
() автор топика
Ответ на: комментарий от nk_lg

Поторопился, $() никак не решил моей проблемы в целом, переменная окружения через system никак не хочет определяться... даже в наколенном скелете:

system("export qwerty=qwerty");
вылетает ошибка...

Вопрос: как грамотно реализовать возврат вполнения system не прибегая к операциям с файлами? Не хочу я каждый раз читать/писать файлы, это уже слишком «долго» будет... ((((

nk_lg
() автор топика
Ответ на: комментарий от nk_lg

как грамотно реализовать возврат вполнения system не прибегая к операциям с файлами?

man popen ; всмысле делать что-то вроде FILE *in;in=popen(«bash -c 'iptables бла-бла-бла | grep ...'»; while(!feof(in)){ /* построчное чтение */ }

или dup/fork/exec/wait как самопальный popen (см K&R), для полного контроля нюансов.. кстати одновременное юзанье pthread_create/join и fork требует значительной аккуратности и вдумчивого чтения ман`ов

system(«export qwerty=qwerty»); очень бредовый бред

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

man popen

Спс...

кстати одновременное юзанье pthread_create/join и fork требует значительной аккуратности и вдумчивого чтения ман`ов

- углубился... похоже в торопях придуманная мной «картина мироздания» требует серьезного переосмысления...

PS.

system(«export qwerty=qwerty»); очень бредовый бред

- ?Почему нельзя или где что почитать касательно сего? Программа запускается от пользователя(root) в его же (пользовательском) пространстве/окружении... почему нельзя придумать, назвать и инициировать свою собственную переменную окружения?

nk_lg
() автор топика
Ответ на: комментарий от nk_lg

при порождении процесса окружение дублируется и потомок далее оперирует только своей копией, не имея права/возможности ни писать, ни читать «родительский» экземпляр. export - встроенная команда shell которая специфичным образом передаёт переменную (помещает в свой env, отмечает как экспортируемую) для непосредственно родительского shell, и этот механизм обмена - сугубо их шелов дело и использовать его в приложениях категорически нерекомендуется.

MKuznetsov ★★★★★
()
17 мая 2015 г.

#include <stdlib.h> #include <stdio.h> #include <pthread.h> #include <string.h>

void* thread_func( char arg[]) { printf(«%s», arg); return 0; }

int main() { int id; pthread_t thread1; printf(«\n--- start first thread--\n»); pthread_create(&thread1, NULL, thread_func(«1»), &id); printf(«\n--- end of start first thread--\n»); printf(«\n--- start second thread--\n»); pthread_create(&thread1, NULL, thread_func(«2»), &id); printf(«\n--- end of start second thread--\n»); printf(«Done\n»);

system(«pause»); return 0; }

anonymous
()
Ответ на: комментарий от anonymous

сишным кастом, некрофил-утырок

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.