LINUX.ORG.RU

Подскажите Аналог WaitForSingleObject(hThread,0)


0

0

Здравствуй, Всемогущий all!

Пишу с использованием Posix threads. Проблема в следующем - в моем приложении основной поток создает дополнительный поток, и ему (основному потоку) иногда нужно проверять - а не закончил ли еще дополнительный поток свою работу?, но чтобы при этом основной поток не останавливал свою работу, то есть pthread_join, увы не подходит. В windows-программировании эту проблему легко решить с помощью вызова WaitForSingleObject(hAdditionalThread,0) - а как это можно сделать в Unix?, и по возможности posix-ными функциями (вроде pthread_tryjoin_np годится, но она непосиксовая :( )?

Подскажите кто знает пожалуйста - ибо решение в виде заведения атомарной или защищенной mutex'ом переменной для статуса потока и последующая работа через нее все же абсолютно не прельщает.

anonymous

В pthreads вроде нет аналога. Либо сделайте pthread_detach, чтобы не джойнить его совсем, либо вызовите join при завершиении программы.

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

anonymous
()

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

anonymous
()
Ответ на: комментарий от anonymous

Вы имеете в виду с помощью функции pthread_getschedparam определять, не завершился ли поток? - то есть если поток завершился, то pthread_getschedparam вернет не 0?

anonymous
()
Ответ на: комментарий от anonymous

Будьте добры, напишите плиз названия функций подписки на события, чтобы мне понять в каком направлении копать

anonymous
()

менять архитектуру приложения, сперва желательно почитать умные книжки [хотя бы Threads Primer].

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

> менять архитектуру приложения, сперва желательно почитать умные >книжки [хотя бы Threads Primer].

Спасибо за совет, правда если все же подскажете название конкретной функции (которую я уже буду искать в умных книжках), то будет совсем здорово

anonymous
()
Ответ на: комментарий от anonymous

> Спасибо за совет, правда если все же подскажете название конкретной функции (которую я уже буду искать в умных книжках), то будет совсем здорово

если бы была такая функция её бы подсказали, чай не звери.
но проблема не в функции, проблема в дизайне.

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

> если бы была такая функция её бы подсказали, чай не звери. > но проблема не в функции, проблема в дизайне.

Вы имеете в виду, что мне стоит перепроектировать приложение так, чтобы не приходилось на ходу определять в основном потоке - не закончилась ли работа дополнительного?

anonymous
()
Ответ на: комментарий от anonymous

> Вы имеете в виду, что мне стоит перепроектировать приложение так, чтобы не приходилось на ходу определять в основном потоке - не закончилась ли работа дополнительного?

именно. запустил поток[и]? хорошо. найди в себе силы дождаться их завершения (pthread_join).

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

Увы, не очень вижу способа, как решить мою задачу без проверки состояния потоков :(. Но это уже выходит за рамки поста. Большое спасибо всем за ответы, тему можно закрыть.

anonymous
()
Ответ на: комментарий от anonymous

> pthread_mutex_trylock

Вы имеете в виде, что если треда уже закончится к моменту вызова pthread_mutex_trylock, то функция вернет ошибку - и это может служить критерием того, работает ли поток?

anonymous
()
Ответ на: комментарий от anonymous

> pthread_mutex_trylock

hm. ну если автора вопроса устроит *try* aka периодический опрос, то тогда уж condvar+mutex. рабочий поток перед завершением взводит условную переменную, а родительский соответственно так или иначе проверяет её через pthread_cond_timedwait(). AFAIU проблема в том, что автор не хочет так делать, i.e. периодически опрашивать рабочей поток умер он уже или ещё нет?

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от rei3er

> но она, естественно, Linux специфичная

а чем она поможет в данной ситуации? вопрос ведь не в том, как пристрелить дочерний поток - он и так сам завершается - а в том, как бы поудобнее об этом узнать в родительском без блокировки на pthread_join() на неопределённое время.

// wbr

klalafuda ★☆☆
()

Открыть один глобальный pipe. Родитель слушает, каждый завершившийся поток пишет свой ид.

anonymous
()
Ответ на: комментарий от klalafuda

обработку сигнала никто не отменял
перед pthread_exit() в дочернем потоке вызываем tkill() и в родительском ловим соответствующий сигнал после чего выполняем требуемые действия

rei3er
()
Ответ на: комментарий от rei3er

> обработку сигнала никто не отменял. перед pthread_exit() в дочернем потоке вызываем tkill() и в родительском ловим соответствующий сигнал после чего выполняем требуемые действия

обработка сигналов в многопоточной программе - это не столь тривиальная тема :-/ родительский поток готов к тому, что его могут прервать в произвольном месте? и что он будет после этого делать? бежать по внутреннему списку запущенных потоков и смотреть опять же по своим флажкам, какой из потоков ещё жив а какой нет? а смысл?

вопрос в том, зачем автору нужно асинхронно завершать дочерние потоки и что он хочет этим добиться. в зависимости от ответа можно советовать ту или иную схему организации приложения. просто так же гадать на кофейной гуще IMHO смысла мало.

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

>вопрос в том, зачем автору нужно асинхронно завершать дочерние >потоки и что он хочет этим добиться. в зависимости от ответа можно >советовать ту или иную схему организации приложения. просто так же >гадать на кофейной гуще IMHO смысла мало.

Да не нужно асинхронно завершать - нужно знать - отработался ли еще дочерний поток или нет. В двух словах приложение - что-то вроде коллектора трафика - приложение принимает траффик по udp и пишет его на лету в базу mysql без индексов, тип таблицы myISAM. По истечении, допустим, данные накопились уже - запускаю индексирование данных в отдельном потоке (на лету с индексами писать нереально, поток слишком сильный). А когда подойдет очередная порция данных через час мне обязательно нужно узнать - закончилось ли индексирование или продолжается пока. В windows-варианте приложения использую WaitForSingleObject, а здесь вот не нашел решения, почему и пришел на форум.

anonymous
()
Ответ на: комментарий от anonymous

> Да не нужно асинхронно завершать - нужно знать - отработался ли еще дочерний поток или нет. В двух словах приложение - что-то вроде коллектора трафика - приложение принимает траффик по udp и пишет его на лету в базу mysql без индексов, тип таблицы myISAM. По истечении, допустим, данные накопились уже - запускаю индексирование данных в отдельном потоке (на лету с индексами писать нереально, поток слишком сильный). А когда подойдет очередная порция данных через час мне обязательно нужно узнать - закончилось ли индексирование или продолжается пока. В windows-варианте приложения использую WaitForSingleObject, а здесь вот не нашел решения, почему и пришел на форум.

ну и замечательно. есть два потока, основной и индексирующий. основной поток создаёт mutex+cond, запускает индексирующий и возвращается к своим делам. индексирующий поток какое-то время работает, после чего по окончанию взводит переменную (pthread_cond_signal) и завершается, переходя в состояние зомби. основной поток в какой-то момент времени, когда ему понадобится узнать, завершилось ли уже индексирование или нет, проверяет состояние cond. он это может делать полностью синхронно через pthread_cond_wait aka блокируясь на переменной, или же асинхронно aka периодически проверяя её состояние через pthread_cond_timedwait. что конкретно выбрать зависит от приложения и его логики. anyway, в какой-то момент времени, когда основной поток таки смог дождаться переменной - wait вернул success - он вызывает pthread_join на дочерний поток для подчистки ресурсов [бо теперь это уже по логики приложения неблокирующая операция] и дальше идёт своей дорогой зная, что индексирование точно завершилось бо рабочий поток ему об этом явно сообщил.

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

ps: да, если у вас основной поток что-то пишет в базу, не вздумайте использовать tkill()/pthread_kill() - libmysqlclient весьма неоднозначно относится к сигналам и прерывание себя, любимой.

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от anonymous


pps: WaitForSingleObject() с нулевым таймаутом на хендл потока - это аналог функций pthread_tryjoin() или pthread_timedjoin() которых нет в POSIX API и, по всей видимости, не будет. но поведение WFSO без особых проблем эмулируется через существующее API посредством штатных механизмов синхронизации как мьютекс и механизмов оповещения о событиях как condition variable. при желании в заданном контексте можно сделать и аналог WaitForMultipleObjects().

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

>pps: WaitForSingleObject() с нулевым таймаутом на хендл потока - это >аналог функций pthread_tryjoin() или pthread_timedjoin() которых нет >в POSIX API и, по всей видимости, не будет. но поведение WFSO без >особых проблем эмулируется через существующее API посредством >штатных механизмов синхронизации как мьютекс и механизмов оповещения >о событиях как condition variable. при желании в заданном контексте >можно сделать и аналог WaitForMultipleObjects().

Если без особых проблем, то может напишете примерно как именно :-[?

anonymous
()
Ответ на: комментарий от klalafuda

> ну и замечательно. есть два потока, основной и индексирующий.

Все понял, спасибо большое!

anonymous
()
Ответ на: комментарий от anonymous

> Если без особых проблем, то может напишете примерно как именно :-[?

на самом деле, всё гораздо проще, и если основному потоку как раз
*не* нужно синхронно ждать завершения индексирующего, то никакие
условные переменные не нужны, достаточно обычного мьютекса:

--- cut ---
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

struct cont {
    pthread_mutex_t mutex;
    int             done;
};

static void *
worker_thread(void *arg)
{
    struct cont *cont = arg;
    printf("Enter worker thread\n");
    sleep(5); // Do some work here
    pthread_mutex_lock(&cont->mutex);
    cont->done = 1;
    pthread_mutex_unlock(&cont->mutex);
    printf("Leave worker thread\n");
    return 0;
}

int
main()
{
    struct cont cont = { .done = 0 };
    pthread_t pth;
    int done = 0;

    printf("Enter main thread\n");
    pthread_mutex_init(&cont.mutex, 0);
    pthread_create(&pth, 0, worker_thread, &cont);
    while (!done) {
        pthread_mutex_lock(&cont.mutex);
        done = cont.done;
        pthread_mutex_unlock(&cont.mutex);
        if (done) {
            printf("Join worker thread\n");
            pthread_join(pth, 0);
        } else {
            printf("Do some work in main thread\n");
            sleep(1); // Do some work here
        }
    }
    pthread_mutex_destroy(&cont.mutex);
    printf("Main thread is done\n");

    return 0;
}
--- cut ---

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

> на самом деле, всё гораздо проще, и если основному потоку как раз > *не* нужно синхронно ждать завершения индексирующего, то никакие > условные переменные не нужны, достаточно обычного мьютекса:

Пример более чем говорящий и предельно понятный. Klalafuda, респект и поклон!

anonymous
()


ps: и не забываем, что в контексте одного соединения libmysqlclient не thread safe. это значит, что в индексирующем потоке нужно заводить или отдельное соединение, или же синхронизировать доступ к существующему. первый вариант по понятным причинам предпочтительнее.

// wbr

klalafuda ★☆☆
()

Попробуйте использовать кондишины : pthread_cond, pthread_wait, pthread_broadcast

the_coder ★★
()
Ответ на: комментарий от klalafuda

> после чего по окончанию взводит переменную (pthread_cond_signal) и завершается, переходя в состояние зомби. основной поток в какой-то момент времени, когда ему понадобится узнать, завершилось ли уже индексирование или нет, проверяет состояние cond. он это может делать полностью синхронно через pthread_cond_wait aka блокируясь на переменной, или же асинхронно aka периодически проверяя её состояние через pthread_cond_timedwait. что конкретно выбрать зависит от приложения и его логики.

Только аккуратно, легко можно нарваться на гонку, если будет несколько вспомогательных потоков.

anonymous
()
Ответ на: комментарий от anonymous

> Только аккуратно, легко можно нарваться на гонку, если будет несколько вспомогательных потоков.

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

// wbr

klalafuda ★☆☆
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.