pthread_join的使用

pthread_join用于阻塞等待某线程的退出,获取其返回值。 任何线程都可以pthread_join等待其他线程,而不一定非要主线程等待子线程。

pthread_join通常用于控制各线程的退出时序,便于资源的有序释放。 有时会遇到一些C模块,在重启或者退出时出Core,尽管并不影响线上服务, 但出Core会触发报警,多多少少让人很不爽。往往都是因为资源的释放时序有问题导致的, 比如一个线程申请的内存,传给另一个线程在使用,如果申请内存的线程提前退出, 若不释放内存,这块内存就泄漏了,若释放内存,可能运算线程还没有使用完,就会导致出Core。 此时有两种处理方案,其一,反正程序都要退出了,内存泄漏就泄漏吧,让操作系统去回收吧, 这样,只需要主线程pthread_join所有线程,内存全都不释放,这不失一种省时省力的好方法; 其二,按照线程之间的内存依赖关系,退出时逐层pthread_join,并释放内存。 其实还有一种比较恶心的方法,就是负责释放内存的线程,先sleep个3秒钟,即等其他处理线程肯定处理完了,再退出, 曾经就遇到过,有程序退出时,有时Core,有时不Core,在某个地方sleep一会,就不再Core了,但明显这种方法太trick了。

举个例子,一个复杂的模块包含查询和更新存储的数据,当然查询的时候包含了复杂的计算,称作计算线程, 共是9个线程,主线程创建了一个epoll线程,负责监听查询端口,建立连接,接收查询请求, 又创建了4个计算线程,负责处理查询请求,又有一个poll线程,负责监听更新端口,接收更新请求, 又有一个更新线程,负责处理更新请求,对了,还有一个Timer线程,负责进行一些定时计算, 比如定时清理脏数据什么的。在这个例子中,查询处理线程和epoll线程是消费者和生产者关系, 是有内存传递的,更新处理线程和poll线程也一样,而定时线程和更新线程以及查询线程是有读写锁共享关系的。 这样在程序退出时,需要epoll线程pthread_join四个查询处理线程,poll线程pthread_join更新处理线程, 主线程pthread_join epoll线程、poll线程和Timer线程。在pthread_join之后,进行内存的释放操作。

pthread_join任意一个线程,会遇到以下几种特殊情形:

  1. 被pthread_join的线程已经退出,此时该函数会立刻返回
  2. 被pthread_join的线程是自己本身,也就是一个线程等待自己退出,该函数不会死锁,也会立刻返回
  3. 被pthread_join的线程正在pthread_join自己,有点拗口,简单地说,就是A、B两个线程互相pthread_join, 但这时,主线程必定要pthread_join它俩,总归会出现,同一个线程被两个线程pthread_join的情况,此时, 这样是不允许的,一个线程的返回状态被一个等待线程取走后,另一个等待它的线程再去取时,就会出错。

下面的代码会出Core,它模拟了一个线程被多个线程pthread_join的情况:

#include <iostream>
#include <stdio.h>
#include <sys/time.h>
#include <pthread.h>
#include <stdint.h>
#include <queue>
#include <unistd.h>
using namespace std;

class Task
{
public:
    int init()
    {
        for (int i=0; i<10; ++i) {
            pthread_create(th+i, NULL, handle, this);
        }
        pthread_create(th+10, NULL, handle2, this);
        return 0;
    }

    int join()
    {
        for (int i=0; i<10; ++i) {
            pthread_join(th[i], NULL);
        }
        return 0;
    }

    void process()
    {
        for (int i = 0; i < 10; ++i) {
            printf("hahha\n");
            sleep(1);
            printf("dede\n");
        }
    }

    void process2()
    {
        printf("thread join begin\n");
        for (int i=0; i<10; ++i) {
            pthread_join(th[i], NULL);
        }
        printf("thread join end\n");
    }

private:
    static void *handle(void *arg)
    {
        ((Task*)arg)->process();
        return NULL;
    }
    static void *handle2(void *arg)
    {
        ((Task*)arg)->process2();
        return NULL;
    }
private:
    pthread_t th[11];
};

int main()
{
    Task task;
    task.init();
    task.join();
    return 0;
}
发表于 2014年09月15日 00:48   评论:0   阅读:2587  



回到顶部

首页 | 关于我 | 关于本站 | 站内留言 | rss
python logo   django logo   tornado logo