Перейти к содержанию
    

Какой аналог у SetEvent в pthread?

Проблема в том, что в библиотеке PThread нет работы с файловыми дескрипторами. Соответственно, для того чтобы одновременно ожидать завершения какой-либо файловой (или сокетовой) операции или поступления управляющего сигнала от другого потока (например, об отмене операции), приходится использовать неименнованные каналы (pipe и write, вместо SetEvent) и функцию poll (предпочитаю ее, а не select). Перерыл кучу книг, в том числе POSIX стандарт, ничего лучше не придумал. Насколько такое решение накладно по ресурсам? Как организовать такое взаимодействие потоков другим способом?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

в 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;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

да. это даже лучше, чем poll, который не для всех устройств реализован. к тому же в вашем коде подчерпнул кое-что для себя, спасибо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

только у меня так:

 

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;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Без 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;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Без mutex есть потенциальные проблемы:

если между проверкой и очисткой возникнет еще одно событие вы его потеряете потому что обнулите args->event.flag = 0;

 

да, опять вы правы.

к тому же не лишним будет это

res = pthread_cond_timedwait(&args->event.event, &args->event.lock, &tm);
        if (res == ETIMEDOUT)
        {
            pthread_cancel(созданный ранее поток, от которого ожидается сигнал);
            return ERR_TIMEOUT;
        }

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не нахожу ответа на свой вопрос... Уточняю условие.

Можно использовать poll, можно select, разницы нет, дело вкуса. Проблема в том, что БЕЗ этих функций невозможно отследить окончание операции с файлом (read, write, recv, send, conect, etc...).

Ситуация следующая. Есть два потока. Один - интерфейс, и там есть кнопка Exit. Другой - работа с сокетами. Работа с сокетами должна быть немедленно прекращена, как только нажали кнопку Exit. Для этого необходимо ждать одновременно и файловый дескриптор (poll/select) и event от pthread (если мы работаем через них). Это невозможно - нет такой функции. В Windows есть такой тип: HANDLE. Он общий и для событий (SetEvent) и для дескрипторов ввода/вывода. Соответственно, оба можно одновременно передать в функцию WaitForMultipleObjects.

Вижу два варианта. Первый: вызывать poll/select с установленным таймаутом в несколько миллисекунд, затем проверять событие и так по кругу. С кнопкой это конечно прокатит, но в случае жесткого реального времени задержка на обработку события будет составлять именно этот таймаут. К тому же постоянное верчение в юзеровском коде не делает чести с точки зрения использования ресурсов и производительности.

Второй вариант: отказаться от синхронизирующих функций pthread нафиг. Использовать pipe. Здесь встает вопрос, насколько эффективно реализованы эти каналы в коде ОС/libc. И не перекрывает ли потенциальная кривая реализация преимуществ над первым вариантом?

Варианты еще?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Второй вариант: отказаться от синхронизирующих функций 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().

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...