LINUX.ORG.RU

Проблема с таймером и сигналами.


0

1

Нужно по истечению времени выполнить функцию, при этом основной поток должен ожидать завершения этой функции.
Проблема в том, что при использовании функции signal(SIG, f) выполнение функции f идет параллельно главному потоку.
Подскажите, как в главном потоке можно дождаться завершения f?

Спасибо.

Нужно что-то вроде pthread_join.

Только вот вы не указали, какой API используете для запуска потоков. Если pthreads - pthread_join поможет.

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

Как мне его правильно использовать? Пробовал в функции f вызвать pthread_create(...), дальше в f и в главном потоке ждать с помощью pthread_join завершения (идентификатор потока определен глобально), но pthread_join всегда возвращает 3, а не 0 :/

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

В мане написано, можно поискать примеры на гитхабе.

pthread_create запускает какую-то другую функцию на выполнение и возвращает дескриптор потока, в котором та функция будет запущена. pthread_join вызывается после pthread_create в создающем потоке, а не в созданном.

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

Моя функция f вызывается по истечению времени, в ней я pthread_create создаю новый поток и функции f жду его завершения, так же в главном потоке тоже его жду, собственно вот код:

#include <iostream>
#include <sys/time.h>
#include <signal.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>
#include <limits.h> // для INT_MAX

using namespace std;

timer_t timerId = 0;
char* data = new char[8*1024*1024];
unsigned int dataPos = 0;
pthread_t m_thread = 0;

void* threadf(void*)
{
    //..
    return 0;
}


void f(int)
{
    timer_delete(timerId);
    timerId = 0;
    
    pthread_create(&m_thread, 0, threadf, 0);
    
    //...
    dataPos = 0;
    pthread_join(m_thread, 0);
}


int main()
{
    //Подключаем функцию sendData к таймеру
    //timer_t timerId;
    struct itimerspec value;
        
    value.it_value.tv_sec = 0;
    value.it_value.tv_nsec = 100000000;
    
    value.it_interval.tv_sec = 0;
    value.it_interval.tv_nsec = 0;
    struct sigevent sevp;
    
    //При истечении времени будет генерироваться SIGALRM
    sevp.sigev_signo = SIGALRM;
    sevp.sigev_notify = SIGEV_SIGNAL;
     
    //Подключем таймер к функции
    signal(SIGALRM, f);
    
    char ch;
    
    do
    {
        pthread_join(m_thread, 0); //Не работает, всегда возвращает 3
        cin.get(ch);
        
        data[dataPos++] = ch;
        
        cin.clear();
        cin.ignore(INT_MAX, '\n');
        
        if(timerId == 0)
            timer_create(CLOCK_REALTIME, &sevp, &timerId);
        timer_settime(timerId, 0, &value, 0);
    }while(true);
    
}

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

А, вот оно что. Прежде всего, во время выполнения обработчика сигнала программа находится в неопределённом состоянии (т.е. она могла быть прервана на середине какого-либо действия), поэтому многие действия в обработчике сигнала выполнять нельзя, в т.ч. создавать потоки.

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

Так что для создания основного цикла советую посмотреть маны, как это делается в чистом C, а не пытаться реализовать это на сигналах. Чувствую, что придётся иметь дело с poll/epoll.

А если вам срочно нужно решение, пусть даже убогое, то заведите переменную

volatile sig_atomic_t triggered = 0;

Пусть начальным её значением будет 0, а обработчик сигнала установит её в 1. А в main() ожидание реализуется таким циклом

while (triggered == 0)
    ;
Минус - загрузка процессора на 100%, пока программа ждёт сигнала.

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

Добавлю ещё sigwait. Но ТС не сказал, что он собирается делать в главном потоке после запуска таймера. Если совсем ничего, то nanosleep или clock_nanosleep — самый простой вариант.

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