Блокировка чтения из файла
Поделитесь почему, возможно решение проблемы лежит на этапе проектирования ? =)
Нет, ждать не будет =), вы же O_NONBLOCK поставили. Вернет управление вашему процессу, возвратом функции по идее будет -1, а errno установится в EAGAIN. Обычно так читаются FIFO файлы или файлы устройств.
Хм. Почему только очереди IPC? Кроме очередей, можете использовать разделяемую память IPC.
Если уж IPC ну ни как вас не устраивает, используйте локальные сокеты или FIFO файлы.
Офф.
У меня такое ощущение что вы каждый раз выдумываете велосипед =), без обиды, правда... в теме "Вызов внешних программ" вы городили тучу вызовов fork и exec, а на предложенный popen даже не взглянули. О нем часто забывают, но ваша проблема бы решалась в несколько строчек кода =). Порой проблема решается проще если рассмотреть вопрос с другого ракурса.
Сейчас у меня это сделано следующим образом - создается файл, открывается писательный дескриптор ( используется всеми потомками для записи вновь пришедшего сообщения). В каждом потомке создаётся читательный дескриптор, после чего в бесконечном цикле aka
while( ( nRead = read( fd, &data, SIZE_DATA ) ) >= 0 ) из файла вынимаются вновь пришедшие данные.... Проблема только в том, что при достижении конца файла вызов не блокируется, а начинает считывать данные размером 0. Вот и приходиться каждый раз просматривать, что я там считал... :)
Была идея помещать приходящие сообщения в очередь ipc, по мере поступления закидывать их в разделяемую память, ставить семафор (что б дождать, пока все активные потомки получат это сообщение), после чего кидать в разделяемую память следующее сообщение и ставить семафор заново - и так по кругу.
На Ваш взгляд последняя идея имеет право на существование? И вобще как бы Вы решили эту задачу?
Я бы делал так. При подключении нового клиента создавал бы отдельный файл для него (или область памяти) и в него бы писался текущий "слепок" разговора всеми потоками пула через семафор. Через заданный промежуток "слепок" отправлялся бы клиенту. Так проще с группами и приватом, да и вообще :) ИМХО, но трафик больше.
Была идея помещать приходящие сообщения в очередь ipc, по мере поступления закидывать их в разделяемую память, ставить семафор (что б дождать, пока все активные потомки получат это сообщение), после чего кидать в разделяемую память следующее сообщение и ставить семафор заново - и так по кругу.
На Ваш взгляд последняя идея имеет право на существование? И вобще как бы Вы решили эту задачу?
Имеет право. И на данный момент для такой схемы придуман паттерн producer/consumer. Примеры его реализации как с семафорами так и с условными переменными есть в нете. Но обычно для реализации используются два семафора.
Вот пример для солярки:
char buf[BSIZE]; // if empty==BSIZE buffer is empty. if empty==0, then it's full
sema_t occupied, empty;
int nextin, nextout;
sema_t pmutex, cmutex;
} BUFFER;
initialization section
BUFFER *bufferp; // allocate a pointer to a BUFFER
bufferp = malloc( sizeof(BUFFER) ); // create a BUFFER type
sema_init(&buffer->occupied, 0, USYNC_THREAD, 0); // force consumer to always wait first
sema_init(&buffer->empty, BSIZE, USYNC_THREAD, 0); // allow for BSIZE accesses, i.e, buf is empty
sema_init(&buffer->pmutex, 1, USYNC_THREAD, 0); // producer mutex
sema_init(&buffer->cmutex, 1, USYNC_THREAD, 0); // consumer mutex
bufferp->nextin = 0; // initialize ring buffer
cond_init( &count_nonzero, USYNC_THREAD, 0); // intraprocesss usage
void producer (BUFFER *b, chare item) {
sema_wait( &b->empty );
sema_wait( &b->pmutex ); // protect against other producers accessing this buffer
b->buf[ b->nextin ] = item; // insert datum
b->nextin = (b->nextin + 1 ) % BSIZE; // ring buffer
sema_post( &b->pmutex ); // allow other producers in
sema_post( &b->occupied ); // let any consumers know a datum is available
}
char consumer(BUFFER *b) {
char item;
sema_wait( &b->occupied ); // wait if another consumer or producer is here
sema_wait( &b->cmutex ); // protect buffer against other consumers
item = b->buf[ b->nectout ]; // get next datum from buffer
b->nextout = (b->nextout + 1) BSIZE; // ring buffer
sema_post( &b->cmutex ); // allow other consumers into this buffer
sema_post( &b->empty ); // let producer know of buffer's status
return ( item );
}
Код не мой, и к сожалению не могу вспомнить откуда брал.
Если чат в локалке, то для общих сообщений можна и broadcast использовать...