я если правильно понимаю фразу "межтредовое" то бишь над расшареной памятью, то трубы тут не применимы/приведут к тормозам; а в качестве очереди можно сделать список, на который поставить семафор доступа.
> я если правильно понимаю фразу "межтредовое" то бишь над расшареной памятью, то трубы тут не применимы/приведут к тормозам; а в качестве очереди можно сделать список, на который поставить семафор доступа.
это не применимо в случае, когда необходимо ждать на пачке разнородных источников событий. например, на сокете и каком-то application specific событии.
Передача чего-то маленького между тредами по трубам даёт возможность юзать один вызов select, ожидая чего-то из труб и из каких-нибудь там сетевых дескрипторов.
Legioner
Ну плохо постоянным движением. Сидеть в select и не дёргаться - это меньше шевелений с тем же результатом. Дёргаться между очередью и poll - это постоянное шевеление. И возникает вопрос баланса: жрать больше проца и быстрее реагировать или наоборот? А селект изящнее - засел в него и без всяких шевелений тебе гарантируется самая быстрая реакция.
почему? если в select передавать в качестве timeout 0, то он с одной стороны не ждёт лишнее время, с другой стороны это не busy waiting, т.к. процессор не грузится.
> если в select передавать в качестве timeout 0, то он с одной стороны не ждёт лишнее время, с другой стороны это не busy waiting, т.к. процессор не грузится.
Ты передал 0 в select, опросил сокет, и... дальше что? Ты начинаешь ждать очереди? тогда ты теряешь время реакции на данные из сокета. Ты опрашиваешь очередь, и потом переходишь к select с 0? Это busy waiting.
>> Ты опрашиваешь очередь, и потом переходишь к select с 0? Это busy waiting.
>Этот вариант. Почему он busy waiting?
Это не просто busy waiting, а извращенный busy waiting, с заходом в ядро! Такое приложение на непреемтабельном ядре даже убить может не сразу получиться...
вот когда будет действительно всё, в том числе, например, семафоры, или хотя бы можно будет свои сущности под файлы маскировать (про запуск потока с пайпом я представляю, но как то криво это), тогда он будет рулить.
> Передача чего-то маленького между тредами по трубам даёт возможность юзать один вызов select, ожидая чего-то из труб и из каких-нибудь там сетевых дескрипторов.
да, всё лишь для select & K. сама по себе передача данных между процессами посредством IPC большого смысла конечно же не несёт.
Ты что-то глобально не понимаешь... Я ж даже строчку "неверную" привел!
Или ты не понимаешь термина busy waiting? Или не знаешь, что такое блокирующее чтение?
Не ест, так как блокируется в read. Видимо fcntl эффекта не возымело тупо. А раз блокируется, то нифига это не активное ожидание. Это вообще гавнищецкое и саксовое ожидание с попадаловом в глубокий read получился (-;
На самом деле я всё это написал потому, что когда то писал на Xlib-е программу, мне там нужен было имитировать события таймера и я делал poll на сокете соединения с Xserver-ом. Видимо там всё таки был не 0, потому что всё работало и не ело процессор. Но я почему то подумал, что 0.
Кстати, на Линуксе возможно извращение с sched_yield();
тогда процесс будет кушать только свободный процессор.
Такое в большинстве современных ядер по умолчанию
будет кушать под 100 процентов, если оно одно, но
если есть конкуренты, оно будет кушать 0 процентов
(но так делать не надо, если не знаешь, зачем):
конкуренты, оно б
#include <sys/select.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sched.h>
int main(void)
{
fd_set read_set;
struct timeval timeout;
int read_rv;
char c;
int sum = 0;
int flags;
FD_ZERO(&read_set);
FD_SET(0, &read_set);
timeout.tv_sec = 0;
timeout.tv_usec = 0;
if (fcntl(0, F_SETFD, O_NONBLOCK) == -1) {
perror("fcntl");
abort();
}
flags = fcntl(0, F_GETFL);
flags |= O_NONBLOCK;
fcntl(0, F_SETFL, flags);
for (;;) {
if (select(1, &read_set, NULL, NULL, &timeout) == -1) {
perror("select");
abort();
}
sched_yield();
read_rv = read(0, &c, 1);
if (read_rv == -1 && errno != EAGAIN) {
perror("read");
abort();
}
if (read_rv == 0) {
break;
}
sum += c;
}
printf("Sum: %d\n", sum);
return 0;
}
Эти условия таковы: куча всего уже засунуто в один селект и тут возникает потребность в какой-то специфической нашей очереди сообщений. Соблазн "засунуть её в тот же селект" может быть реализован трубопрокатностью. Соблазн продиктован неприятием поллинга и излишних шевелений.
В ситуации с селектом пайпы -- классический паттерн, иначе проблема просто труднорешаемая, никакой поллинг тут не поможет, разве что перебивать селект сигналом из другой нитки (верх изящества!)
Мне реально встречалась ситуация, когда пришлось общаться пайпами просто потому, что нитка при определенных условиях могла форкаться.
> Может лучше сказать "иногда программируют форкание из треда", а то как-то самопроизвольно форкающийся тред чё-то пугает )
:-) Терминологический вопрос!
Мой сленг коробит кривая вилка, а слова "самопроизвольно" там не было. В нитке происходит вызов форка => нитка форкнулась т.е., раздвоилась (со всем адресным пространством), ИМХО понятно...
>>Использование универсальной функции, пригодной на все случаи жизни.
>Например!
Ну, хочется тебе некий IPC протокол свой наваять, чтобы и на кластер вставал, и на SMP, а на SMP вместо процессов часто логичнее треды юзать...