6

我正在使用 posix 线程在 C 中使用固定数量的线程处理程序。

当线程由于某些错误而终止时,如何通知我?

有信号可以检测吗?

如果是这样,信号处理程序是否可以创建一个新线程以保持线程数相同?

4

6 回答 6

1
  1. 使线程分离
  2. 让他们优雅地处理错误。即关闭互斥锁、文件等...

那么你就没有问题了。

也许向主线程发射一个 USR1 信号,告诉它事情已经变成梨形了(我想说山雀向上!)

于 2012-05-04T09:28:11.307 回答
1

使用您提供的最新输入,我建议您执行以下操作来获取特定进程已启动的线程数-

#include<stdio.h>
#define THRESHOLD 50

int main ()
{
    unsigned count = 0;
    FILE *a;

    a = popen ("ps H `ps -A | grep a.out | awk '{print $1}'` | wc -l", "r");
    if (a == NULL)
        printf ("Error in executing command\n");

    fscanf(a, "%d", &count );

    if (count < THRESHOLD)
    {
        printf("Number of threads = %d\n", count-1);
            // count - 1 in order to eliminate header.
            // count - 2 if you don't want to include the main thread

        /* Take action. May be start a new thread etc */
    }

    return 0;
}

备注

  • ps H显示所有线程。

  • $1打印在我的系统 Ubuntu 上显示 PID 的第一列。列号可能会因系统而异

  • a.out其替换为您的进程名称

  • 反引号将评估其中的表达式并为您提供进程的 PID。我们正在利用所有 POSIX 线程将具有相同 PID 的事实。

于 2012-05-04T10:53:54.657 回答
1

通过将函数指针传递给中间函数来创建线程。异步启动该中间函数并让它同步调用传递的函数。当函数返回或抛出异常时,您可以以任何您喜欢的方式处理结果。

于 2012-05-04T09:41:17.580 回答
1

我怀疑当线程因任何原因死亡或退出时,Linux 会向您发出信号。您可以手动执行此操作。

首先,让我们考虑两种线程结束的方式:

  • 它自行终止
  • 它死了

在第一种方法中,线程本身可以告诉某人(比如线程管理器)它正在被终止。然后线程管理器将产生另一个线程。

在第二种方法中,看门狗线程可以跟踪线程是否处于活动状态。这或多或少是这样完成的:

Thread:
    while (do stuff)
        this_thread->is_alive = true
        work

Watchdog:
    for all threads t
        t->timeout = 0
    while (true)
        for all threads t
            if t->is_alive
                t->timeout = 0
                t->is_alive = false
            else
                ++t->timeout
                if t->timeout > THRESHOLD
                    Thread has died! Tell the thread manager to respawn it
于 2012-05-04T11:40:19.343 回答
1

如果由于任何原因无法采用 Ed Heal 的“正常工作”方法(这是我对 OP 问题的最喜欢的答案,顺便说一句),那么懒惰的狐狸可能会看看pthread_cleanup_push()andpthread_cleanup_pop()宏,并考虑包括整个线程函数的主体在这两个宏之间。

于 2012-05-04T15:10:11.987 回答
1

知道线程是否完成的干净方法是调用pthread_join()该线程。

// int pthread_join(pthread_t thread, void **retval);
int retval = 0;
int r = pthread_join(that_thread_id, &retval);
... here you know that_thread_id returned ...

问题pthread_join()是,如果线程永远不会返回(继续按预期运行),那么您将被阻止。因此,这在您的情况下不是很有用。

但是,您实际上可以检查是否可以加入(tryjoin),如下所示:

//int pthread_tryjoin_np(pthread_t thread, void **retval);
int retval = 0;
int r = pthread_tryjoin_np(that_thread_id, &relval);

// here 'r' tells you whether the thread returned (joined) or not.
if(r == 0)
{
   // that_thread_id is done, create new thread here
   ...
}
else if(errno != EBUSY)
{
   // react to "weird" errors... (maybe a perror() at least?)
}
// else -- thread is still running

还有一个定时加入,它将等待您指定的时间,例如几秒钟。根据要检查的线程数以及您的主进程是否处于其他位置,这可能是一个解决方案。在线程 1 上阻塞 5 秒,然后在线程 2 上阻塞 5 秒,等等。对于 1,000 个线程,每个循环需要 5,000 秒(大约需要 85 分钟来处理所有线程以及管理事物所需的时间......)

手册页中有一个示例代码,它显示了如何使用 pthread_timedjoin_np() 函数。您所要做的就是放置一个 for 循环来检查每个线程。

struct timespec ts;
int s;

...

if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
 /* Handle error */
}

ts.tv_sec += 5;

s = pthread_timedjoin_np(thread, NULL, &ts);
if (s != 0) {
   /* Handle error */
}

如果你的主进程有其他事情要做,我建议你不要使用定时版本,尽可能快地遍历所有线程。

于 2016-05-10T00:20:03.133 回答