LINUX.ORG.RU

Как правильно сделать?


0

0

Есть один процесс. Пусть Мастер. Есть куча процессов пусть Slave. Нужно чтобы один мастер, ставил какой-то флаг, по которому запускались бы (получали бы квант шедулера) Slave. Пробовал через именованный семафор. Получается на красиво, нужно на каждый Slave заводить свой семафор, А я не знаю сколько будет Slaveвов, и не хочу заниматься ловлей ситуаций два "слейва на одном семафоре". Какие еще пути есть?

Положи pthread_cond_t в расшаренную память (не забудь накинуть соответствующий атрибут) и дергай pthread_cond_broadcast.

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

> Положи pthread_cond_t в расшаренную память (не забудь накинуть соответствующий атрибут) и дергай pthread_cond_broadcast.

У меня НЕ нити. Отдельные задачи. Со своим стеком, хипом, UID итд.

Artem-Dnepr
() автор топика
Ответ на: комментарий от mannaz

У меня НЕ The process-shared attribute. У меня разные задачи. И разные процессы. Обмен данными, через шаред мемори. Шарить мемеори может 1...хоть 1000 задач. Нужно всем им послать сообщение.

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

> У меня разные задачи. И разные процессы.

Замечательно!

> Обмен данными, через шаред мемори.

Вот и положи туда pthread_cond_t и поставь мастером на него PTHREAD_PROCESS_SHARED.

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

Тоесть если у меня задача-slave сдохнет во время ожидания wait, после mutex_lock, то у меня сдохнет все? Очень не хорошее решение.

Что еще можно придумать?

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

> Но пришлось разрешить slave писать в шареную память. :( :( :(

Ну можно сделать кусочек памяти для синхронизации с доступом на запись, а остальную память с данными оставить на чтение.

const86 ★★★★★
()
Ответ на: комментарий от Artem-Dnepr

> Тоесть если у меня задача-slave сдохнет во время ожидания wait, после mutex_lock, то у меня сдохнет все?

Мьютекс нужен только для того, чтобы эксклюзивно изменять/проверять условие. Для твоей задачи (в текущей ее постановке) для ожидания будет достаточной последовательность вызовов:

pthread_mutex_lock(mutex);
pthread_cond_wait(cond, mutex); // почитай man
pthread_mutex_unlock(mutex);

Если нужна защита от любых "вдруг что-то сдохнет", то готовых рецептов никакой API тебе не предоставит. В реальных условиях при ожидании обычно идет завязка на какие-нибудь таймауты, по истечении которых срабатывает та или иная стратегия восстановления, резервирования и т.д. Подключай голову, короче, и Стивенса не забудь почитать.

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

> Ну можно сделать кусочек памяти для синхронизации с доступом на запись, а остальную память с данными оставить на чтение.

И что это поменяет? Подыхает один из клиентов, ставится раком вся система.

Artem-Dnepr
() автор топика
Ответ на: комментарий от mannaz

> pthread_mutex_lock(mutex); Тут она может сдохнуть, или ее банально может кто-то прибить. > pthread_cond_wait(cond, mutex); // почитай man > pthread_mutex_unlock(mutex);

> Если нужна защита от любых "вдруг что-то сдохнет", то готовых рецептов никакой API тебе не предоставит. В реальных условиях при ожидании обычно идет завязка на какие-нибудь таймауты, по истечении которых срабатывает та или иная стратегия восстановления, резервирования и т.д. Подключай голову, короче, и Стивенса не забудь почитать.

Это усложнение. Сложно== не хорошо == не надежно. Я придумал только пускать по UDP на 127.0.0.1 боардкаст. Но это же маразм! Но зато более портируемо чем модуль в кернел писать.

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

> Это усложнение

> Сложно == не хорошо == не надежно


> Я придумал пускать по UDP на 127.0.0.1 боардкаст


Мде... До свидания.

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

> Мде... До свидания.

Нуашо? Какие еще варианты? Я придумать ничего не могу, хотя и совершенно точно понимаю что UDP это идиотизм.

Artem-Dnepr
() автор топика

Ннннндааа. Может стоит пересмотреть дизайн своего ПО. По моему тут изврат какой-то.

anonymous
()

Pipes или лучше Unix sockets? Slave спит на блокирующем чтении. Мастер записывает комманду. Slave просыпается и начинает выполнять комманду. Что-то в там духе подойдет?

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

> Нуашо? Какие еще варианты? Я придумать ничего не могу, хотя и совершенно точно понимаю что UDP это идиотизм.

Ты сначала объясни, чем тебя настолько не устраивает вариант с pthread_cond_t с точки зрения надежности, что ты решил ступить на скользкую дорожку половых извращений с TCP/IP.

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

> настолько не устраивает вариант с pthread_cond_t 1. Я не хочу давать доступ на запись прикладным задачам к реал-таймовому процессу. 2. Я хочу исключить возможность блокировки прикладной задачей более приоритетного процесса. 3. Я не хочу при поиске глюков, даже рассматривать возможность того, что прикладная задача может внести какие-то изменения в основной процесс. 4. Я хочу иметь возможность безболезненно вынести прикладную задачу куда-то по сети. В этом случае UDP будет весьма к стати.

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

> Pipes или лучше Unix sockets? Slave спит на блокирующем чтении. Мастер записывает комманду. Slave просыпается и начинает выполнять комманду. Что-то в там духе подойдет?

Не подойдет. Так как слейвов может быть очень много. Все они будут висеть на блокирующем чтении. Но проснется только один, который висит дольше, или имеет больший приоритет. (это про пайп. если просто сокет, то он не откроется, так как будет занят.)

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

> 4. Я хочу иметь возможность безболезненно вынести прикладную задачу куда-то по сети

Тебе стоило начать с этого, Артем-Днепр

mannaz
()

Может сигналами воспользоватся?

Все slave процессы сгруппировать.
В слейв процессах ждать сигнала с помощью sigsuspend.
Мастер с помощью kill посылает сигнал всем slave процессам.

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

> Тебе стоило начать с этого, Артем-Днепр Но это глубоко "на потом". И что именно по сети гнать, под большим вопросом. Просто можно не просто 12345 по ЮДП гнать, а что-то полезное, что потом пригодится.

Но просто какой-то дебилизм. Это же ПРОСТО, и ЭЛЕМЕНТАРНО решается и в ядре линуха, и на любом контроллере, под какимнить ucos и вообще где угодно. А под линухом, в юзер-спейсе, какой-то дебилизм. Простейшая задача а как сигналить, не понятно совершенно.

Artem-Dnepr
() автор топика
Ответ на: комментарий от Devix

А сигналов разве не ограниченное кол-во? Сейчас гляну. Я думал что по сигналу можно только какую-то функцию вызвать, как прерывание.

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

> А сигналов разве не ограниченное кол-во?

Да ограничено. Для этого можешь использовать SIGUSR1.

> Я думал что по сигналу можно только какую-то функцию вызвать, как

прерывание.

Создай функцию которая будет ловить SIGUSR1 в ней сделай чтобы устонавливался глобальный флаг. И при помощи sigsuspend в цыкле жди изменение глобального флага.

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

> Да ограничено. Для этого можешь использовать SIGUSR1.

SIGRTMIN+n выглядит логичнее.

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

> А под линухом, в юзер-спейсе, какой-то дебилизм

Где дебилизм-то? Я пока вижу только твое непонимание IPC в UNIX. Вот три вызова:

pthread_mutex_lock(mutex);
pthread_cond_wait(cond, mutex);
pthread_mutex_unlock(mutex);

Объясни, где твой "slave" может запороть "master'а", только без капса, пожалуйста.

> Простейшая задача а как сигналить, не понятно совершенно


Дык говорю же: Стивенса почитай.

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

> Объясни, где твой "slave" может запороть "master'а", 1. Запороть данные в shared memory. (дать ему RO я не могу) 2. Сделать pthread_mutex_lock(mutex); и зависнуть.

Как сделать красиво, я уже разобрался, читаю про сигналы. Всем спасибо.

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

> 1. Запороть данные в shared memory

Тут ты прав. Если помимо вызова этих трех функций, использующих немного расшаренной на R/W памяти, ты напишешь свой код, который запарывает данные, то они испортятся.

2. Сделать pthread_mutex_lock(mutex) и зависнуть

Кажется до меня начало доходить. Ты всерьез переживаешь, что процесс "зависнет" между вызовами pthread_mutex_lock (который захватывает мьютекс) и pthread_cond_wait (который освобождает мьютекс _до_ ожидания и захватывает обратно уже после поступления события)? Тогда да, UDP и сигналы - это глобально и надежно.

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

> Ты всерьез переживаешь, что процесс "зависнет" между вызовами pthread_mutex_lock (который захватывает мьютекс) и pthread_cond_wait (который освобождает мьютекс _до_ ожидания и захватывает обратно уже после поступления события)?

Вполне реальная возможность. Процессу и SIGKILL может снаружи прилететь аккурат где-то там, неприятно будет.

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

> Кажется до меня начало доходить. Ты всерьез переживаешь, что процесс "зависнет" между вызовами pthread_mutex_lock (который захватывает мьютекс) и pthread_cond_wait (который освобождает мьютекс _до_ ожидания и захватывает обратно уже после поступления события)? Тогда да, UDP и сигналы - это глобально и надежно.

Совершенно верно. Процесс просто может вызвать pthread_mutex_lock, где-то, непонятно где, и непонятно как, и потом непонятно что сделать. Кроме того, эти программы вполне могут быть написаны не мной, а человеком который эти все нити первый раз видит и имеет обо всем этом весьма странное представление. Зачем мне этот цирк, если я могу без него обойтись? Мне лично кажется, что гораздо логичнее сделать так, что прикладные программы запущенные под определенным UID или GID будут получать определенные сигналы типа SIGRTMIN+n, и или обрабатывать эти сигналы или просто самоубиваться, если этот обработчик не обрабатывается. Этот вариант мне кажется гораздо более гибким. Как его реализовать я и разбираюсь.

Artem-Dnepr
() автор топика
Ответ на: комментарий от kemm

> Вполне реальная возможность. Процессу и SIGKILL может снаружи прилететь аккурат где-то там, неприятно будет.

Я не говорю о том, что это нереально. И без SIGKILL существует достаточно факторов, которые могут заставить программу работать неправильно. Если требуется, большинство из них можно учесть: будь то перехват сигналов (не SIGKILL, конечно), ожидание с таймаутом и т.д.
Смущает больше отсутствие корреляции между уровнем надежности, которого ТС хотел бы достичь своими силами, и его компетенцией.

mannaz
()
Ответ на: комментарий от Artem-Dnepr

> Процесс просто может вызвать pthread_mutex_lock, где-то, непонятно где, и непонятно как, и потом непонятно что сделать

Да я понял уже: у тебя код, как песня льется

> Кроме того, эти программы вполне могут быть написаны не мной, а человеком который эти все нити первый раз видит и имеет обо всем этом весьма странное представление


Напиши для него функцию wait_master()

> Мне лично кажется, что гораздо логичнее сделать так, что прикладные программы запущенные под определенным UID или GID будут получать определенные сигналы типа SIGRTMIN+n, и или обрабатывать эти сигналы или просто самоубиваться, если этот обработчик не обрабатывается. Этот вариант мне кажется гораздо более гибким. Как его реализовать я и разбираюсь.


ok

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

> Смущает больше отсутствие корреляции между уровнем надежности, которого ТС хотел бы достичь своими силами, и его компетенцией.

Не Вам об этом судить.

Artem-Dnepr
() автор топика
Ответ на: комментарий от mannaz

> Да я понял уже: у тебя код, как песня льется

Вы не правильно поняли. Я просто человек, которому свойственно делать ошибки.

> Напиши для него функцию wait_master()

Зачем, если этого можно избежать? Принципиальные возражения против того что я предложил (сигналы) будут?

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

> Не Вам об этом судить

В вопросе о том, судить мне или нет о какаких-либо вещах, я разберусь самостоятельно. И давай на "ты".

> Принципиальные возражения против того что я предложил (сигналы) будут?


Нет. Если по-мелочи, то мне кажется странным, что уже имея, по твоим словам, обмен данными через расшаренную между процессами память, ты решил заморочиться еще и с сигналами.

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

> В вопросе о том, судить мне или нет о какаких-либо вещах, я разберусь самостоятельно. И давай на "ты".

На "Ты", обычно общаются равные люди.

> Нет. Если по-мелочи, то мне кажется странным, что уже имея, по твоим словам, обмен данными через расшаренную между процессами память, ты решил заморочиться еще и с сигналами.

1. Если Вы знаете более быстрый и менее накладный обмен, то я его не знаю. 2. Так уж получилось, что для x86, и вообще систем с MMU/MPU я писал сравнительно не много, и обмен через общую память, мне как-то привычнее. 3. Уже писал, мне нужен строго односторонний обмен. 4. Проект судя по всему долгоиграющий, и заранее раскладывать себе грабли, мне не хочется. 5. Сигналы, это часть POSIX, и выходить за рамки каких-то стандартов, которые в случае необходимости помешают мне перетащить систему куда-то, мне не хочется.

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

>если просто сокет, то он не откроется, так как будет занят.)

Ты овощ. Кем занят? Читай теорию про Unix sockets (Просьба не путать с TCP sockets). Один сервер (он же Мастер) и клиенты (они же slave) соединяются с сервером. Сервер обслуживает каждого клиента в отдельности. Самое главное, что сервер точно знает сколько и какие slave присутствуют в системе, и будут нормально отработаны все ситуации с падением slave.

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

Это значит, на сервере нужно заводить по отдельной нити на каждого клиента. И может быть я так и сделаю. Ибо с сигналами тоже не так просто оказалось. А работать через сеть, тоже было бы не плохо.

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

Я не очень люблю многонитевые сервера. Мне кажется во многих случаях лучше использовать poll или select. Они позволяют делать все тоже самое, но в одном процессе и меньше геммороя с синхронизацией. Если правильно все написать, то все очень хорошо маштабируется.

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

На мой взгляд величина задержек не имеет значения. Правда я использую неблокирующее чтение/запись. При этом частично собранные данные хранятся в буфере. В этот буфер заполняется по мере поступления данных. В промежутках между получением порций данных этот поток может отрабатывать и другие полезные операции. Например он может обслуживать другое соединение или проверять таймауты на предмет совершения периодических операций. Все это в рамках одного потока. Системный вызов poll (при грамотной реализации) это позволяет.

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

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

На мой взгляд величина задержек не имеет значения.

Удобство влияет и прозрачность.

Правда я использую неблокирующее чтение/запись. При этом частично собранные данные хранятся в буфере. В этот буфер заполняется по мере поступления данных. В промежутках между получением порций данных этот поток может отрабатывать и другие полезные операции. Например он может обслуживать другое соединение или проверять таймауты на предмет совершения периодических операций. Все это в рамках одного потока.

И чем вызван этот мазохизм? Нити такие страшные?

У меня в большинстве случаев, данные которые требуются, глубоко асинхронные, вообще и задержка на их получение может быть от меньше чем микросекунда до десятков секунд и больше. Мне проще и на клиенте, открыть несколько нитей которые будут сосать данные из сервера, и кидать собощения ГУИ, по доступности. Вообще, я больше по железу спец, или по программизму своих же железок. Может я что-то и не так делаю. Готов слушать любые советы. К примеру почему куча нитей так плохо?

void *serverThread(void *th)
{
	//puts("Server Start");
	usleep(10000);
	printf("-");
	//free(th);
	pthread_exit( NULL );
	
	
};


void start_server(void)
{
	int i;
	//int ret = pthread_create(&threadServer,NULL, serverThread,(void *)0);
	pthread_t *th = malloc(sizeof(pthread_t));
	
	for(i=0;i<1000000;i++)
	{
		printf("+");
		
		//int ret = pthread_create(&threadServer,NULL, serverThread,(void *)0);
		int ret = pthread_create(&th,NULL, serverThread,(void *)th);
		pthread_detach(th);
		printf(".%i.",ret);
		
		//usleep(100);
	}
}



Проверил, все нормально работает.

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

>Удобство влияет и прозрачность.

Ты не поверишь. Но все может быть очень удобно и прозрачно. Без мазохизма. Проверено на практике. Пользу я ощутил от однонитевой обработки на одном большом и сложном проекте, хотя начал именно с multithread.

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

В принципе multithread тоже вариант. Только он требует высокого профессионализма и дисциплины. Нужно просто НЕ СОВЕРШАТЬ ошибок, по причине того, что некоторые ошибки невероятно трудно исправить из-за их непредсказуемости.

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

У меня довольно простая логика работы. В обшем если против нитий нет возражения, то и ладно.

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