Pthreads и сигналы - PullRequest
       4

Pthreads и сигналы

0 голосов
/ 23 марта 2011

У меня небольшие проблемы с нитями. По сути, я хочу поймать SIGINT и очистить все потоки и выйти. Что у меня есть (скелетный код):

main.c:

sig_atomic_t running;

void handler(int signal_number)
{
    running = 0;
}

int main(void)
{
    queue job_queue = new_job_queue();

    running = 1;

    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = &handler;
    sigaction(SIGINT, &sa, NULL);

    /* create a bunch of threads */
    init_threads(&job_queue);

    while(running) {
        /* do stuff */
    }

    cleanup();

    return (0);
}

threads.c

extern sig_atomic_t running;
pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER;
sem_t queue_count;

void init_threads(queue *q)
{
    int numthreads = 12; /* say */

    sem_init (&queue_count, 0, 0);

    pthread_t worker_threads[numthreads];

    int i;
    for(i=0;i<numthreads;i++)
        pthread_create(&worker_threads[i], NULL, &thread_function, q);
}

void * thread_function(void *args)
{
    pthread_detatch(pthread_self());

    queue *q = (queue *)args;

    while(running) {

        job *j = NULL;

        sem_wait(&queue_count);

        pthread_mutex_lock(&queue_mutex);
        j = first_job_in_queue(q);
        pthread_mutex_unlock(&queue_mutex);

        if(j) {
            /*do something*/
        }

    }

    return (NULL);
}

Мне немного повезло с этим. Поскольку вы не уверены, какая нить получает сигнал, я подумал, что это хороший путь. Но у меня есть проблема, где sem_wait() в threads.c висит, что ожидается, но не желательно. Цикл while(running) в threads.c кажется избыточным. Должен ли я сделать pthread_kill() для всех потоков из основного? Есть ли очевидные проблемы с приведенным выше скелетным кодом? Есть ли лучший / более простой способ сделать это?

Спасибо.

Ответы [ 4 ]

2 голосов
/ 23 марта 2011

Что вы можете сделать, это вызвать sem_post() из обработчика, пока все потоки не будут разблокированы.В функции потока, сразу после sem_wait(), вы должны проверить значение переменной running и, если это будет нулевой разрыв, то время.

Код в обработчике может выглядеть примерно так:

int sval;    
sem_getvalue(&queue_count, &sval);
while (sval < 0) {
    sem_post(&queue_count);
    sem_getvalue(&queue_count, &sval);
}

Конечно, возвращаемые значения должны быть проверены на ошибки

1 голос
/ 07 ноября 2012

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

0 голосов
/ 23 марта 2011

Вы не должны делать pthread_kill(), если вам не нужно. Я не знаком с pthread_detatch(), но если вы хотите, чтобы ваша функция main() ожидала завершения потоков, вероятно, было бы лучше, если бы ваша функция cleanup() выполняла pthread_join() для каждого идентификатора потока. возвращается из pthread_create(), чтобы дождаться нормального завершения каждого потока.

Кроме того, насколько я могу судить, sem_wait() зависает, потому что ваше значение семафора инициализируется равным 0. Если вы хотите, чтобы не более 5 потоков одновременно обращались к общему ресурсу, инициализируйте семафор до 5, т.е. sem_init(&queue_count, 0, 5).

0 голосов
/ 23 марта 2011

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

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

...