Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Какой аналог у SetEvent в pthread?
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > Программирование
Andrey_Sudnov
Проблема в том, что в библиотеке PThread нет работы с файловыми дескрипторами. Соответственно, для того чтобы одновременно ожидать завершения какой-либо файловой (или сокетовой) операции или поступления управляющего сигнала от другого потока (например, об отмене операции), приходится использовать неименнованные каналы (pipe и write, вместо SetEvent) и функцию poll (предпочитаю ее, а не select). Перерыл кучу книг, в том числе POSIX стандарт, ничего лучше не придумал. Насколько такое решение накладно по ресурсам? Как организовать такое взаимодействие потоков другим способом?
KRS
в 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
да. это даже лучше, чем poll, который не для всех устройств реализован. к тому же в вашем коде подчерпнул кое-что для себя, спасибо.
RCray
только у меня так:

Код
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
Без mutex есть потенциальные проблемы:
если между проверкой и очисткой возникнет еще одно событие вы его потеряете потому что обнулите args->event.flag = 0;

Цитата(2b|!2b?.. @ May 15 2008, 14:08) *
Код
    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
Цитата(KRS @ May 15 2008, 16:16) *
Без 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
Не нахожу ответа на свой вопрос... Уточняю условие.
Можно использовать poll, можно select, разницы нет, дело вкуса. Проблема в том, что БЕЗ этих функций невозможно отследить окончание операции с файлом (read, write, recv, send, conect, etc...).
Ситуация следующая. Есть два потока. Один - интерфейс, и там есть кнопка Exit. Другой - работа с сокетами. Работа с сокетами должна быть немедленно прекращена, как только нажали кнопку Exit. Для этого необходимо ждать одновременно и файловый дескриптор (poll/select) и event от pthread (если мы работаем через них). Это невозможно - нет такой функции. В Windows есть такой тип: HANDLE. Он общий и для событий (SetEvent) и для дескрипторов ввода/вывода. Соответственно, оба можно одновременно передать в функцию WaitForMultipleObjects.
Вижу два варианта. Первый: вызывать poll/select с установленным таймаутом в несколько миллисекунд, затем проверять событие и так по кругу. С кнопкой это конечно прокатит, но в случае жесткого реального времени задержка на обработку события будет составлять именно этот таймаут. К тому же постоянное верчение в юзеровском коде не делает чести с точки зрения использования ресурсов и производительности.
Второй вариант: отказаться от синхронизирующих функций pthread нафиг. Использовать pipe. Здесь встает вопрос, насколько эффективно реализованы эти каналы в коде ОС/libc. И не перекрывает ли потенциальная кривая реализация преимуществ над первым вариантом?
Варианты еще?
vshemm
Цитата(Andrey Sudnov @ May 18 2008, 07:59) *
Второй вариант: отказаться от синхронизирующих функций pthread нафиг. Использовать pipe. Здесь встает вопрос, насколько эффективно реализованы эти каналы в коде ОС/libc. И не перекрывает ли потенциальная кривая реализация преимуществ над первым вариантом?

А ОС, собственно, какая?
Впрочем, если не нравятся пайпы, можно использовать сокеты smile.gif Для них есть высокоэффективная реализация оповещения об изменении состояния, правда, механизмы в разных ОС разные. Гляньте сюда - 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.

однако, про локальные сокеты он почему-то не упоминает.

И еще smile.gif Вы зря,имхо, предпочитаете poll select'у, т.к. poll при каждом вызове гоняет структу в ядро => большой оверхед. С другой стороны селект имеет ограничени на кол-во дескрипторов. Во всяком случае в linux это так, поэтому и появился epoll().
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.