多线程中的资源释放
2013-11-08 16:19
1036 查看
代码中的问题
最近在写多线程的代码,这段程序虽然不要求像服务器软件一样不间断的长期运行,但是运行的时间也可能达到数天。这段代码的功能大概是一个线程A负责分配一块内存,然后填充数据,交给另一个线程B进行处理,线程B处理之后将内存释放。功能很简单,但是问题出现了,测试的时候发现内存持续增长,没有下降的迹象(就好象内存从来没有被释放一样),使用valgrind这样的工具检查居然没有发现内存泄漏,真是奇怪呀!后来找到了原因,问题在于线程A在创建线程B的时候使用了joinable线程,并在A结束之前调用pthread_join来等待所有的B结束。B是joinable类型的线程,这样的线程中释放的内存是不会马上被系统回收的,要等到pthread_join之后才会被回收。这样上面的现象就好解释了,每一个B在运行结束之后它释放的内存并没有被系统回收,这样随着A不断的分配内存并产生新的B,系统占用的内存越来越多。但是在整个程序结束的时候A使用了pthread_join来连接了每个B,所以在A结束的时候所有被释放的内存才一起被系统回收,所以实际上并没有内存泄漏,这样valgrind也就没有检查出内存泄漏。
线程属性
man page中的描述
先看看linux关于pthread_create的描述:A thread may either be joinable or detached. If a thread is joinable, then another thread can call pthread_join(3) to wait for the thread to terminate and fetch its exit status. Only when a terminated joinable thread has been joined are the last of its resources released back to the system. When a detached thread terminates, its resources are automatically released back to the system: it is not possible to join with the thread in order to obtain its exit status. Making a thread detached is useful for some types of daemon threads whose exit status the application does not need to care about. By default, a new thread is created in a joinable state, unless attr was set to create the thread in a detached state (using pthread_attr_setdetachstate(3)).
从手册的描述中可以看出线程分为joinable和detached两种,并且两种线程对于资源的释放方式是不同的,我们上面的问题也就是由于用错了线程类型造成的。
joinable类型的线程
从man手册中可以看出,在不使用属性指定detached的情况下使用pthread_create创建线程就是joinable线程,它需要pthread_join来连接:pthread_create(&tid, NULL, thread_func, NULL);
这样就创建了一个joinable线程。
detached类型的线程
man手册中说创建detached类型的线程需要线程属性,并且调用pthread_attr_setdetachstate函数来设置detached属性:pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(&tid, &attr, thread_func, NULL);
这样就创建了一个detached类型的线程,这样的线程不需要使用pthread_join来等待其结束,也不能够使用pthread_join来等待其结束。
除了在创建的时候指定detached属性来创建detached类型的线程之外,还可以使用pthread_detach函数将一个joinable类型的线程分离,使它变成detached类型的线程。有两种方式可以达到这种目的。现在假设线程A创建了一个joinable类型的线程B,要使用pthread_detach函数将B分离。
第一种方式是A创建B之后调用pthread_detach:
pthread_create(&tid, NULL, thread_func, NULL); pthread_detach(tid);
这样线程B(也就是线程函数thread_func)变成了detached类型的线程。
第二种方式是B被创建之后自己调用pthread_detach来分离自己:
线程A的代码:
pthread_create(&tid, NULL, thread_func, NULL);
线程B的代码:
void* thread_func(void* args) { pthread_detach(pthread_self()); ... }
这样线程B就分离了自己。
这两种方式不能够同时使用,因为pthread_detach函数分离的对象只能是joinable类型的线程,否则会失败。
pthread_join和pthread_detach的含义
joinable和detached两种类型的函数也对应着pthread_join和pthread_detach两个函数,这两个函数其实是与线程的资源释放类型相关的,由这两个函数来决定资源释放的时机。线程被创建之后必须调用其中一种来释放资源。detached类型的线程结束之后系统自动的回收了资源,但是joinable类型的线程如果创建它的线程没有调用pthread_join那么这就是真正的资源泄漏。pthread_exit还是return?
关于多线程代码的资源释放还有一个有趣的问题,进程中的主线程提前结束并退出,这时候其他的子线程还没有完成自己的工作,这个时候会发生什么呢?其他的子线程立即退出,整个进程退出还是进程等到每一个子线程结束之后再退出呢?这要看看pthread_exit的man手册:
Performing a return from the start function of any thread other than the main thread results in an implicit call to pthread_exit(), using the function’s return value as the thread’s exit status. To allow other threads to continue execution, the main thread should terminate by calling pthread_exit() rather than exit(3). The value pointed to by retval should not be located on the calling thread’s stack, since the contents of that stack are undefined after the thread terminates.
这样就清楚了,在子线程中pthread_exit和return是一样的,但是在main函数中不行,return会被替换成exit,这导致了进程直接终止,那么此时没有结束的子线程就会被迫停止,所以要让main退出时子线程继续运行就必须在main中使用pthread_exit来代替return。
相关文章推荐
- C++多线程环境下注意共享资源的释放顺序
- 多线程下关于硬件资源的释放问题
- 狗尾续貂:利用引用计数在多线程中安全释放资源
- QTcpServer多线程资源释放
- 在多线程中释放List所占用的资源-List.removeall(List);
- ArcGIS Engine中正确释放打开资源
- C# 中using 用来释放资源的用法
- Win8 XAML 自定义控件资源加载与释放窍门
- c# winform编程之多线程ui界面资源修改总结篇
- flume使用(五):taildirSource重复获取数据和不释放资源解决办法
- ArcGIS Engine中正确释放打开资源
- 请手动释放你的资源
- 关于MappedByteBuffer资源释放问题
- Java通过继承Thread类实现多线程 ,处理同一个共享资源
- httpclient连接池释放异常和多余资源
- 浅谈C#托管程序中的资源释放问题
- 多线程共享资源冲突
- 使用java钩子,应用退出时释放资源
- c# winform编程之多线程ui界面资源修改总结篇
- Windows XP 共享限制及手工释放会话资源的方法