ant2009
ant2009

Reputation: 22696

cancelling or killing a pthread

gcc (GCC) 4.6.3
valgrind-3.6.1

I have created a application that send and receives some messages in 2 different thread for sending and receiving. Using pthreads, condition varables and mutexes for locks.

However, the sender will send messages and then signal the receiver to receive it and process it. It does this in a while loop.

However, the problem occurs if I want to quit the application by using ctrl-c and handling the interupt. If there is no messages being sent then the receiver is stuck in the while loop waiting to receive.

The main thread will call join and block waiting for the receiver to finish. But it doesn't as it waiting on the pthread_cond_wait.

I was thinking of using the pthread_cancel or pthread_kill. But I don't like to do that as it doesn't allow the thread to exit normally.

many thanks for any suggestions.

main function

    void main(void)
    {
        /* Do some stuff here */

    /* Start thread that will send a message */
    if(pthread_create(&thread_recv_id, &thread_attr, thread_recv_fd, NULL) == -1) {
        fprintf(stderr, "Failed to create thread, reason [ %s ]",
            strerror(errno));
            break;
        }
        printf("Start listening for receiving data'\n");

        /* Start thread to receive messages */
        if(pthread_create(&thread_send_id, &thread_attr, thread_send_fd, NULL) == -1) {
            fprintf(stderr, "Failed to create thread for receiving, reason [ %s ]",
                    strerror(errno));
            break;
        }

    /* Clean up threading properties */
    pthread_join(thread_send_id, NULL);
    pthread_join(thread_recv_id, NULL); <---- blocking here waiting for the recv thread to finish

    pthread_mutex_destroy(&mutex_queue);
    pthread_cond_destroy(&cond_queue);

    return 0;
}

sender thread

void *thread_send_fd()
{
        pthread_mutex_lock(&mutex_queue);
        if(send_fd((int)fd) == FALSE) {
            /* Just continue to send another item */
            continue;
        }
        /* Signal the waiting thread to remove the item that has been sent */
        pthread_cond_signal(&cond_queue);

        pthread_mutex_unlock(&mutex_queue);
}

receiver thread

void *thread_recv_fd()
{
    while(is_receiving()) {
        pthread_mutex_lock(&mutex_queue);

        /* Wait for an item to be sent on the queue */
        pthread_cond_wait(&cond_queue, &mutex_queue); <---- waiting here

        queue_remove();
        pthread_mutex_unlock(&mutex_queue);
    }

    pthread_exit(NULL);
}

Upvotes: 2

Views: 11782

Answers (1)

Anthony Williams
Anthony Williams

Reputation: 68701

You basically have 3 choices:

  1. Use pthread_cancel. This will interrupt the pthread_cond_wait call, and then exit the thread, invoking the cancellation handlers registered with pthread_cleanup_push on the way up.

  2. Use pthread_kill to send a signal to the thread. This doesn't "kill" the thread, it just sends a signal. In this case, you must have registered a signal handler in that thread for the signal you use, and that signal handler must do something to tell the thread to exit. This isn't particularly better than the third option, since the signal handler still needs to do something to make the pthread_cond_wait loop exit.

  3. Add a manual interruption feature to your thread that knows to set a flag and signal the condition variable. The loop around pthread_cond_wait should then check the flag and exit the thread if the flag is set.

I would recommend (1) or (3). Using pthread_cancel is most generic, but requires careful handling in the thread to ensure there are suitable pthread_cleanup_push calls for cleaning up all resources allocated by the thread, unlocking all mutexes, and so forth. Writing a manual interruption feature is potentially more work, but can be most easily tailored to your application.

Upvotes: 9

Related Questions