gcc 4.4.3 c89 pthreads
我使用valgrind来检查内存错误。
我只是想知道是否有任何linux工具可以检测程序完成后尚未终止的正在运行的线程。
我正在运行一个多线程应用程序,需要一个工具来确保所有线程都已完成。
非常感谢任何建议,
答案 0 :(得分:15)
如果程序已终止(因为初始线程从main()
返回,某个线程称为exit()
,或者进程收到致命信号),那么可以保证所有线程都已终止极端偏见。
如果你想编写你的程序,以便确保所有线程都在main()
退出之前退出,那么你需要在{{{{}}结束时遍历所有线程。 1}},在每个人身上调用main()
。 (这也意味着你不应该创建分离的线程,或者分离它们。)
答案 1 :(得分:7)
工具方法
你可以使用Valgrind来帮助解决这个问题(通过它的Helgrind工具),但它需要对代码进行微小的修改。对于每个线程,在创建线程时使线程锁定为唯一的互斥锁,并在线程退出时释放互斥锁。然后,当在Helgrind下运行时,如果线程在程序终止时没有退出,则会收到警告,因为线程仍将锁定到互斥锁。考虑这个示例线程启动例程:
void * thread_start (void *arg)
{
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&mutex);
// ...
// Here the thread does whatever it normally does
// ...
// Unlock the mutex before exiting
pthread_mutex_unlock(&mutex);
}
只需使用Valgrind的Helgrind工具运行程序,如下所示:
$ valgrind --tool=helgrind ./<program-name>
如果程序终止时线程没有退出,那么Helgrind会发出如下警告:
==2203== Thread #2 was created ==2203== at 0x31C96D3CDE: clone (in /lib64/libc-2.5.so) ==2203== by 0x31CA206D87: pthread_create@@GLIBC_2.2.5 (in /lib64/libpthread-2.5.so) ==2203== by 0x4A0B206: pthread_create_WRK (hg_intercepts.c:229) ==2203== by 0x4A0B2AD: pthread_create@* (hg_intercepts.c:256) ==2203== by 0x40060A: main (main.c:26) ==2203== ==2203== Thread #2: Exiting thread still holds 1 lock ==2203== at 0x4005DD: thread_start (main.c:13) ==2203== by 0x4A0B330: mythread_wrapper (hg_intercepts.c:201) ==2203== by 0x31CA20673C: start_thread (in /lib64/libpthread-2.5.so) ==2203== by 0x31C96D3D1C: clone (in /lib64/libc-2.5.so)
如果你没有在线程可能退出的任何地方添加互斥锁解码代码(例如使用pthread_exit
),你将会使用这种方法得到误报,但是一旦识别出这种假阳性就很容易。
另类方法(推荐)
说完上述所有内容后,这可能不是我自己采取的方法。相反,我会编写程序,使无法终止,直到所有线程都退出。实现此目的的最简单方法是在从pthread_exit
返回之前从主线程调用main
。这样做意味着只要任何其他线程仍在运行,该进程将保持活动状态。
如果您采用这种方法,并且该过程在您预期时不会退出,那么您就知道线程仍在运行。然后,您可以将调试器附加到进程,以确定哪些线程仍在运行以及它们正在执行的操作。
答案 2 :(得分:6)
如果您打算使用Boost。线程库,则可以使用.join()
方法。
#include <boost/thread/thread.hpp>
#include <iostream>
void hello()
{
std::cout <<
"Hello world, I'm a thread!"
<< std::endl;
}
int main(int argc, char* argv[])
{
boost::thread thrd(&hello);
thrd.join();
return 0;
}
答案 3 :(得分:6)
在这个类似的问题中有一个简单的技巧:Multiple threads in C program
如果从main调用pthread_exit,则在所有其他线程完成之前,您的进程不会退出。
答案 4 :(得分:4)
原始答案已更新,以解决pthread_exit()
方案。
假设您想要在pthread_join()
返回之前判断所有线程是否main()
- 正确,有以下几种方法:
在gdb
下运行它并在main()
的最后一行中断,然后查看“threads”命令的输出。应该只有主线。
创建一个使用包装器覆盖pthread_create
的共享库,该包装器保存计数器的启动次数。线程包装器递增计数器并调用实际线程函数,并且当线程返回或退出时,用pthread_create_key()
注册的函数将递减它。库析构函数将检查计数器是否为零,这意味着它们都被终止。将其与LD_PRELOAD=checker.so ./your_executable
的可执行文件一起使用(无需修改代码)。
在Debian 5.0.5上测试。
#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
/* thread-local storage key */
static pthread_key_t tls_key = 0;
static int counter = 0;
static pthread_mutex_t g_mutex;
/* TLS destructor prototype */
void on_thread_end(void*);
void __attribute__ ((constructor))
init_checker()
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutex_init(&g_mutex, &attr);
pthread_mutexattr_destroy(&attr);
pthread_key_create(&tls_key, &on_thread_end);
}
void __attribute__ ((destructor))
finalize_checker()
{
int remain;
pthread_mutex_lock(&g_mutex);
remain = counter;
pthread_mutex_unlock(&g_mutex);
pthread_mutex_destroy(&g_mutex);
if (remain)
fprintf(stderr, "Warning: %d threads not terminated\n", remain);
pthread_key_delete(tls_key);
}
/* thread function signature */
typedef void* (*ThreadFn)(void*);
struct wrapper_arg
{
ThreadFn fn;
void* arg;
};
/* TLS destructor: called for every thread we created
when it exits */
void
on_thread_end(void *arg)
{
free(arg);
pthread_mutex_lock(&g_mutex);
--counter;
pthread_mutex_unlock(&g_mutex);
}
static void*
thread_wrapper(void *arg)
{
void *ret;
struct wrapper_arg *warg;
warg = (struct wrapper_arg*)arg;
/* Thread started, increment count. */
pthread_mutex_lock(&g_mutex);
++counter;
pthread_mutex_unlock(&g_mutex);
/* set thread-specific data to avoid leaks
* when thread exits
*/
pthread_setspecific(tls_key, arg);
/* Run the actual function. */
ret = (*warg->fn)(warg->arg);
/* Thread finishes, TLS destructor will be called. */
return ret;
}
/* pthread_create signature */
typedef int (*CreateFn)(pthread_t*,const pthread_attr_t*,ThreadFn,void*);
/* Overriding phtread_create */
int
pthread_create(
pthread_t *thread,
const pthread_attr_t *attr,
ThreadFn start_routine,
void *arg)
{
CreateFn libc_pthread_create;
struct wrapper_arg *warg;
/* Get a handle to the real function. */
libc_pthread_create
= (CreateFn)dlsym(RTLD_NEXT, "pthread_create");
if (!libc_pthread_create)
return -1;
/* Wrap user function. */
warg = malloc(sizeof(struct wrapper_arg));
if (!warg)
return -1;
warg->fn = start_routine;
warg->arg = arg;
/* Create a thread with a wrapper. */
return libc_pthread_create(thread, attr, &thread_wrapper, warg);
}
CFLAGS+=-fpic -O3
checker.so: checker.o
gcc -shared -Wl,-soname,$@ -o $@ $^ -ldl -lpthread
答案 5 :(得分:3)
如果错误,请纠正我,但在所有正在运行的线程结束之前,程序才会完成。
答案 6 :(得分:2)
您不需要任何外部工具:我会使用简单的信号量跟踪线程。
1)将其设置为使其初始计数与线程数相同:
sem_init( &semThreadCount, 0, threadCount );
2)修改你的线程以“通知”他们正在优雅地退出:
sem_wait( &semThreadCount );
3)你可以在线程完成或信号量为0时退出,或者只打印剩余的信号量值并退出,这将是仍在运行的线程的数量:
int v;
sem_getvalue( &semThreadCount, &v );
通过这种方式,您可以确保在退出时没有线程仍在运行,或者通过一些日志记录,可以在退出后知道哪些线程仍在运行。
请记住sem_destroy
sempahore。
答案 7 :(得分:1)
如果您不能使用C ++并因此无法使用KMan的答案,那么您也可以使用“C”API加入分离的pthread。 (加入意味着等待分离的线程完成他们的工作。)
请参阅pthread tutorial。
答案 8 :(得分:1)
可以使用waitpid
检查进程的存在,即是否仍有任何线程在运行。
如果您只是希望您的进程继续使用所有线程,但您不再需要main
,那么您可以通过pthread_exit
结束该线程。除了明确的exit
或简单的return
之外,这不会终止您的其他线程。
答案 9 :(得分:1)
此类工具已存在。在Linux上,您可以使用ps
或top
。在Windows上,好的任务管理器完成工作:只需检查您的流程是否仍然存在:
答案 10 :(得分:0)
如果它们是线程(而不是进程),那么您只需检查进程是否正在运行,因为线程在进程内运行。
您可以使用ps -ef检查进程是否正在运行,然后将结果通过管道传输到grep中以查找您的特定进程。
答案 11 :(得分:0)
如果你想要一个外部方法来观察你的进程执行的线程,在Linux上你可以查看/ proc /(pid)/ task。这就是像ps(1)或top(1)这样的方法工具。
答案 12 :(得分:0)
你错过了重要部分:
除非所有线程都已终止,否则程序无法退出。
但是,在退出之前,您应该对所有线程执行pthread_join()
。这可确保所有线程终止,并允许您free()
所有相应的pthread_t
,以便您不会泄漏内存。
如果说,valgrind
可以为您提供有关您之后没有清理过的线程的全面视图。使用--leakcheck=full
运行它,并确保不会留下各种结构。这些将表明有一个线程没有完全正确终止。