如何正确管理pthread

时间:2019-03-03 17:09:28

标签: c pthreads embedded-linux pthread-join

有时会出现一些随机问题,以加入pthread。我只能说,连接失败时,线程不会因互斥而陷入死锁。加入时发生超时时,大多数情况下线程处于空闲状态(睡眠syscall)。

我的需求是基本的。一种从主线程启动/停止线程的方法。因此,我不需要将互斥锁放在pthread状态变量的启动/停止管理器中。线程大多数时候都作为无限循环运行。我所有的线程都使用相同的框架进行设计。启动和停止功能。线程函数定义。我有一个全局变量 g_event_ctx 来存储线程的当前状态。 运行,知道我需要取消它。 is_joinable 来了解我是否需要加入该线程。而且我在所有线程函数上都具有睡眠/读取/写入系统调用(取消点!)

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;

框架代码:

   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;
    }

线程函数的骨架:

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 是一个宏,用于检查条件以确定是否需要跳转以标记错误

什么原因可以解释 pthread_timedjoin_np 上的超时?另一段破坏我的线程ID的代码?我的骨架中存在设计问题吗?

1 个答案:

答案 0 :(得分:0)

您可以通过在上下文结构中放置一个变量来指示您希望后台线程停止,在调用join之前在主线程中设置该变量,并在后台线程中定期检查该变量,退出while( 1)循环,如果是真的。 如果您有任何阻塞性调用永久休眠,则可以使它们超时并使用while(!want_to_stop)进行循环,或者对于select循环,添加一个文件描述符,您可以在想要停止时从主线程激活它。 eventfd或管道)。