【问题标题】:Rerunning cancelled pthread重新运行已取消的 pthread
【发布时间】:2015-01-22 04:41:33
【问题描述】:

我的问题是我无法重用已取消的 pthread。示例代码:

#include <pthread.h>

pthread_t alg;
pthread_t stop_alg;
int thread_available;

void *stopAlgorithm() {
    while (1) {
        sleep(6);
        if (thread_available == 1) {
            pthread_cancel(alg);
            printf("Now it's dead!\n");
            thread_available = 0;
        }
    }
}
void *algorithm() {
    while (1) {
        printf("I'm here\n");
    }
}

int main() {
    thread_available = 0;
    pthread_create(&stop_alg, NULL, stopAlgorithm, 0);
    while (1) {
        sleep(1);
        if (thread_available == 0) {
            sleep(2);
            printf("Starting algorithm\n");
            pthread_create(&alg, NULL, algorithm, 0);
            thread_available = 1;
        }
    }
}

此示例应创建两个线程 - 一个将在程序开始时创建,并在启动时尝试取消第二个线程,第二个应在取消后立即重新运行并说“我在这里”。但是,当算法线程一旦不再启动就取消时,它会说“正在启动算法”并且什么也不做,不再有“我在这里”的消息。能否请您告诉我如何再次启动已取消(立即停止)的线程?

UPD:所以,感谢您的帮助,我明白了问题所在。当我重新运行算法线程时,它会抛出错误 11:“系统缺少创建另一个线程所需的资源,或者将超出系统对进程 PTHREAD_THREADS_MAX 中线程总数的限制。”。实际上我有 5 个线程,但只有一个被取消,其他的由 pthread_exit 停止。因此,在算法停止并且程序进入待机模式后,我使用pthread_join 检查了所有线程的状态 - 所有线程显示 0(已取消显示 PTHREAD_CANCELED),据我所知,这意味着所有线程都已成功停止。但是再次尝试运行算法会再次引发错误 11。所以我检查了内存使用情况。在算法之前处于待机模式 - 10428,在算法期间,当所有线程使用时 - 2026m,在算法停止后处于待机模式 - 2019m。因此,即使线程停止它们仍然使用内存,pthread_detach 对此也无济于事。线程后还有其他清理方法吗?

另外,有时在 pthread_cancel 上,我的程序会因“必须安装 libgcc_s.so.1 才能使 pthread_cancel 正常工作”而崩溃

【问题讨论】:

  • 使用取消点正确取消线程。测试函数返回代码并打印失败原因。确保 thread_available 变量访问是同步的。解决所有这些问题后,如果问题仍然存在,请发布代码和程序输出。
  • 如果我理解正确,你建议我在算法函数中使用 stop_flag。但是我应该在每一步都做这些标志,这就是为什么我使用 pthread_cancel 而不是 exit
  • 第二次调用pthread_start的返回值(和errno的值)是多少?
  • 我不是在谈论标志。请阅读:man7.org/linux/man-pages/man7/pthreads.7.html 取消点 至少,将 pthread_testcancel 调用添加到算法函数并在取消请求处于活动状态时退出循环。
  • 或者为了确保线程取消,我可以等到 pthread_join 状态变为“PTHREAD_CANCELLED”。谢谢

标签: c multithreading pthreads embedded-linux


【解决方案1】:

几点:

首先,这是不安全的:

int thread_available;

void *stopAlgorithm() {
    while (1) {
        sleep(6);
        if (thread_available == 1) {
            pthread_cancel(alg);
            printf("Now it's dead!\n");
            thread_available = 0;
        }
    }
}

至少出于某些原因,它不安全。首先,您没有将thread_available 标记为易失性。这意味着编译器可以优化stopAlgorithm 以读取一次变量,并且永远不会重新读取它。其次,您没有确保对它的访问是原子的,或者由互斥锁保护它。要么声明它:

volatile sig_atomic_t thread_available;

(或类似的),或者更好的是,通过互斥锁来保护它。

但是对于从另一个线程触发的一般情况,您最好使用条件变量(和互斥锁),在侦听线程中使用pthread_condwaitpthread_condtimedwait,在触发线程中使用pthread_condbroadcast

接下来,stopAlgorithm 线程的意义何在?它所做的只是在 0 到 6 秒之间不可预测的时间后取消 algorithm 线程?为什么不直接从主线程发送pthread_cancel

接下来,你是否关心你的算法在被取消时在哪里?如果没有,只需pthread_cancel 即可。如果是这样(无论如何,我认为它要好得多),请定期检查一个标志(如上面的原子和易失性,或受互斥体保护)和pthread_exit(如果已设置)。如果您的算法每秒左右执行大块,那么请检查它。如果它做了很多微小的事情,请每 1,000 次操作检查一次(比如说),这样使用互斥体就不会带来性能损失。

最后,如果你取消了一个线程(或者如果它是pthread_exits),你再次启动它的方式就是再次调用pthread_create。然后是一个运行相同代码的新线程。

【讨论】:

  • 我上面写的代码只是我感兴趣的大程序部分的一个例子。也许我应该写更多的代码作为例子。第一个线程是算法,第二个是失败检查,所以他们都不能等待。如果发生故障,算法应在任何步骤立即停止。而我的问题实际上是在你答案的最后一部分 - 我取消了线程,但是当我尝试再次创建它时它不会启动,尽管 thread_available 为 0 并且出现了关于启动算法的消息
  • 根据您的示例很难判断。在重新启动线程之前,您应该pthread_join 取消的线程。试试看。
  • 我的评论对于这个领域来说太大了,请阅读 UPD 部分
  • 内存屏障需要互斥锁。 volatileisn'tenough.
  • 我不需要内存屏障,让它随用随用,但线程完成或取消后释放内存
猜你喜欢
  • 1970-01-01
  • 2013-06-17
  • 1970-01-01
  • 2015-03-11
  • 1970-01-01
  • 1970-01-01
  • 2011-05-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多