简体   繁体   English

如何正确管理pthread

[英]How to manage properly pthread

I have some random issues sometimes to join pthread.我有时会遇到一些随机问题来加入 pthread。 I can just say that the thread is not stuck in a deadlock with a mutex when the join is failing.我只能说当连接失败时,线程没有陷入带有互斥锁的死锁。 Most of the time the thread is idle (sleep syscall) when the timeout occurred on join.大多数时候线程空闲(睡眠系统调用)时加入超时。

My need is basic.我的需求是基本的。 A way to start/stop a thread from the main thread.一种从主线程启动/停止线程的方法。 So I don't need to put mutex in start/stop manager on pthread state variable.所以我不需要在 pthread 状态变量的启动/停止管理器中放置互斥锁。 The thread is working as an infinite loop most of the time.该线程大部分时间都在无限循环中工作。 All my thread are designed with the same skeleton.我所有的线程都是用相同的骨架设计的。 A start and stop function.一个启动和停止功能。 The thread function definition.线程函数定义。 I have a global variable g_event_ctx to store the current status of the thread.我有一个全局变量g_event_ctx来存储线程的当前状态。 running to know I need to cancel it.跑着知道我需要取消它。 is_joinable to know if I need to join the thread. is_joinable知道我是否需要加入线程。 Moreover I have sleep/read/write syscall on all my thread function (cancel point !)此外,我的所有线程函数都有睡眠/读/写系统调用(取消点!)

typedef struct pthread_context
{
    pthread_t id;       /*!< pthread_t to be able to stop the thread later */
    int running;        /*!< allow to know if the thread is currently running */
    int is_joinable;    /*!< allow to know if the thread is joinable */
} str_pthread_context;

The code of the skeleton :骨架代码:

   int start_x_manager (void)
    {
        pthread_t t_x;

        if (g_event_ctx.x_thread.is_joinable) return 0;

        PRINT_INFO ("Start x manager");

        // start push x thread
        if (pthread_create (&t_x, NULL, x_loop_thread, NULL))
            PRINT_ERR_GOTO ("error on pthread_create for x thread");
        pthread_setname_np(t_x, "x");
        g_event_ctx.x_thread.id = t_x;
        g_event_ctx.x_thread.is_joinable = 1;
        g_event_ctx.x_thread.running = 1;
        return 0;
    error:
        g_event_ctx.x_thread.running = 0;
        g_event_ctx.x_thread.is_joinable = 0;
        return 1;
    }

    int stop_x_manager (void)
    {
        struct timespec ts;

        if (!g_event_ctx.x_thread.is_joinable) return 0;
        PRINT_INFO ("Stop x manager");

        if (g_event_ctx.x_thread.running)
        {
            CHECK_ERR_GOTO (pthread_cancel(g_event_ctx.x_thread.id) != 0, "Cannot cancel x thread");
            g_event_ctx.x_thread.running = 0;
        }
        CHECK_ERR_GOTO (clock_gettime(CLOCK_REALTIME, &ts) == -1, "Cannot get clock time");
        ts.tv_sec += 5;
        CHECK_ERR_GOTO (pthread_timedjoin_np (g_event_ctx.x_thread.id, NULL, &ts) != 0, "Cannot join x_thread");
        g_event_ctx.x_thread.is_joinable = 0;
        return 0;
    error:
        g_event_ctx.x_thread.running = 0;
        g_event_ctx.x_thread.is_joinable = 0;
        return 1;
    }

The skeleton of the thread function :线程函数的骨架:

void *x_loop_thread (void *arg __attribute__((__unused__)))
{

    CHECK_ERR_GOTO (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0, "Cannot set cancel state");
    CHECK_ERR_GOTO (pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0, "Cannot set cancel state");

    PRINT_INFO ("Start x manager loop thread ...");

    pthread_cleanup_push(x_manager_cleanup, some_stuff);

    while (1)
    {
         // Do some stuff here
    }
    g_event_ctx.x_thread.running = 0;
    pthread_exit (NULL);
  error:
    g_event_ctx.x_thread.running = 0;
    pthread_cleanup_pop(1);
    pthread_exit (NULL);
}

CHECK_ERR_GOTO is a macro which check a condition to know if I need to jump to label error . CHECK_ERR_GOTO是一个宏,它检查条件以了解我是否需要跳转到标签错误

What is the reason which can explain a timeout on the pthread_timedjoin_np ?可以解释pthread_timedjoin_np超时的原因是什么? Another piece of code which corrupted my thread id ?另一段破坏了我的线程 id 的代码? Is there a problem of design in my skeleton ?我的骨架有设计问题吗?

You can sidestep the problem by putting a variable in the context structure indicating you want the background thread to stop, setting that variable in your main thread before calling join, and checking that variable periodically in the background thread, exiting the while(1) loop if it's true.您可以通过在上下文结构中放置一个变量来指示您希望后台线程停止,在调用 join 之前在主线程中设置该变量,并在后台线程中定期检查该变量,退出 while(1) 循环来回避问题如果这是真的。 If you have any blocking calls that sleep forever, you can either have them time out and loop them with while(!want_to_stop) or, for select loops, add a file descriptor you can activate from the main thread when you want to stop (an eventfd or pipe).如果您有任何永远休眠的阻塞调用,您可以让它们超时并使用while(!want_to_stop)循环它们,或者,对于选择循环,添加一个文件描述符,您可以在想要停止时从主线程激活(一个eventfd 或管道)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM