Andrey_Sudnov 0 13 мая, 2008 Опубликовано 13 мая, 2008 · Жалоба Проблема в том, что в библиотеке PThread нет работы с файловыми дескрипторами. Соответственно, для того чтобы одновременно ожидать завершения какой-либо файловой (или сокетовой) операции или поступления управляющего сигнала от другого потока (например, об отмене операции), приходится использовать неименнованные каналы (pipe и write, вместо SetEvent) и функцию poll (предпочитаю ее, а не select). Перерыл кучу книг, в том числе POSIX стандарт, ничего лучше не придумал. Насколько такое решение накладно по ресурсам? Как организовать такое взаимодействие потоков другим способом? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 0 14 мая, 2008 Опубликовано 14 мая, 2008 · Жалоба в POSIX есть mutex и Condition Variables я когда игрался с POSIX под сигвин делал примерно так: typedef struct { pthread_mutex_t lock; pthread_cond_t event; bool flag; }event_t; static inline void event_init(event_t* event) { pthread_mutex_init(&event->lock,0); pthread_cond_init(&event->event,0); event->flag=false; } static inline void event_set(event_t* event) { pthread_mutex_lock(&event->lock); if (!event->flag) { event->flag=true; pthread_cond_signal(&event->event); } pthread_mutex_unlock(&event->lock); } static inline bool event_wait(event_t* event, unsigned s_timeout) { bool r; pthread_mutex_lock(&event->lock); if(!event->flag) { if (s_timeout) { timespec_t timer; clock_gettime(CLOCK_REALTIME,&timer); timer.tv_sec+=s_timeout; pthread_cond_timedwait(&event->event,&event->lock,&timer); }else { do { pthread_cond_wait(&event->event,&event->lock); }while(!event->flag); } } r=event->flag; event->flag=false; pthread_mutex_unlock(&event->lock); return r; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RCray 0 15 мая, 2008 Опубликовано 15 мая, 2008 · Жалоба да. это даже лучше, чем poll, который не для всех устройств реализован. к тому же в вашем коде подчерпнул кое-что для себя, спасибо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RCray 0 15 мая, 2008 Опубликовано 15 мая, 2008 · Жалоба только у меня так: void* child_func(void* arg) { struct args_t* args = (args*)arg; args->size = read(args->fd, args->packet, args->supposed_size); args->event.flag = 1; pthread_cond_signal(&args->event.event); return 0; } int parent(struct args_t *args) { pthread_t child; struct timespec tm; if ( pthread_create(&child, NULL, child_func, args) != 0 ) return ERR_CREATE; // задание таймаута ... while(!args->event.flag) { res = pthread_cond_timedwait(&args->event.event, &args->event.lock, &tm); if (res == ETIMEDOUT) return ERR_TIMEOUT; } args->event.flag = 0; return args->errors; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 0 15 мая, 2008 Опубликовано 15 мая, 2008 · Жалоба Без mutex есть потенциальные проблемы: если между проверкой и очисткой возникнет еще одно событие вы его потеряете потому что обнулите args->event.flag = 0; while(!args->event.flag) { res = pthread_cond_timedwait(&args->event.event, &args->event.lock, &tm); if (res == ETIMEDOUT) return ERR_TIMEOUT; } args->event.flag = 0; return args->errors; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RCray 0 15 мая, 2008 Опубликовано 15 мая, 2008 · Жалоба Без mutex есть потенциальные проблемы: если между проверкой и очисткой возникнет еще одно событие вы его потеряете потому что обнулите args->event.flag = 0; да, опять вы правы. к тому же не лишним будет это res = pthread_cond_timedwait(&args->event.event, &args->event.lock, &tm); if (res == ETIMEDOUT) { pthread_cancel(созданный ранее поток, от которого ожидается сигнал); return ERR_TIMEOUT; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Andrey_Sudnov 0 18 мая, 2008 Опубликовано 18 мая, 2008 · Жалоба Не нахожу ответа на свой вопрос... Уточняю условие. Можно использовать poll, можно select, разницы нет, дело вкуса. Проблема в том, что БЕЗ этих функций невозможно отследить окончание операции с файлом (read, write, recv, send, conect, etc...). Ситуация следующая. Есть два потока. Один - интерфейс, и там есть кнопка Exit. Другой - работа с сокетами. Работа с сокетами должна быть немедленно прекращена, как только нажали кнопку Exit. Для этого необходимо ждать одновременно и файловый дескриптор (poll/select) и event от pthread (если мы работаем через них). Это невозможно - нет такой функции. В Windows есть такой тип: HANDLE. Он общий и для событий (SetEvent) и для дескрипторов ввода/вывода. Соответственно, оба можно одновременно передать в функцию WaitForMultipleObjects. Вижу два варианта. Первый: вызывать poll/select с установленным таймаутом в несколько миллисекунд, затем проверять событие и так по кругу. С кнопкой это конечно прокатит, но в случае жесткого реального времени задержка на обработку события будет составлять именно этот таймаут. К тому же постоянное верчение в юзеровском коде не делает чести с точки зрения использования ресурсов и производительности. Второй вариант: отказаться от синхронизирующих функций pthread нафиг. Использовать pipe. Здесь встает вопрос, насколько эффективно реализованы эти каналы в коде ОС/libc. И не перекрывает ли потенциальная кривая реализация преимуществ над первым вариантом? Варианты еще? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vshemm 0 18 мая, 2008 Опубликовано 18 мая, 2008 · Жалоба Второй вариант: отказаться от синхронизирующих функций pthread нафиг. Использовать pipe. Здесь встает вопрос, насколько эффективно реализованы эти каналы в коде ОС/libc. И не перекрывает ли потенциальная кривая реализация преимуществ над первым вариантом? А ОС, собственно, какая? Впрочем, если не нравятся пайпы, можно использовать сокеты :) Для них есть высокоэффективная реализация оповещения об изменении состояния, правда, механизмы в разных ОС разные. Гляньте сюда - http://monkey.org/~provos/libevent/ Так или иначе, задержки будут намного меньше таймаута в неск. миллисекунд при небольшом количестве сокетов. Варианты еще? Сигналы? А вот что пишет Steven Grimm (http://monkeymail.org/archives/libevent-users/2007-January/000450.html): no UNIX-ish system I'm aware of has an equivalent to the Windows WaitForMultipleObjects API that allows you to wake up on semaphores / condition variables and on input from the network. Without that, any solution is going to end up using pipes (or maybe signals, which have their own set of issues in a multithreaded context) to wake up the libevent threads. однако, про локальные сокеты он почему-то не упоминает. И еще :) Вы зря,имхо, предпочитаете poll select'у, т.к. poll при каждом вызове гоняет структу в ядро => большой оверхед. С другой стороны селект имеет ограничени на кол-во дескрипторов. Во всяком случае в linux это так, поэтому и появился epoll(). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться