Linux下用线程pthread加速程序

来源:互联网 发布:mac恢复模式 terminal 编辑:程序博客网 时间:2024/05/16 12:23

自从上次写了数学之美之分形——C++及OpenCV实现Julia集和Mandelbrot集绘制,还有用OpenMP加速你的程序——以分形绘制为例之后,一直耿耿于怀啊,为什么不能自己实现多进程或者线程编程实现程序的加速呢。

终于,OS课程上学会了线程还有进程编程,现在,就以线程为例来实现程序的加速吧!

首先,得介绍下线程,Linux中的线程实际上就是轻量级的进程,CPU调度的时候是以线程调度的,而一个进程可以拥有多个线程,然后统一由内核统一调度。

(注意,Linux早期版本中没有实现线程,比如Linux0.11,只有进程,如果各位有兴趣,不妨试试自己去实现下内核级线程。)


然后是几个主要的线程库函数:

int pthread_attr_init(pthread_attr_t *attr);用默认值初始化attr指向的pthread_attr_t结构。pthread_attr_t主要定义了创建线程时需要用户提供的属性信息,pthread_create()根据这些信息创建线程。函数成功时返回0,出错时返回错误号。当然调用之后需要销毁, pthread_attr_destroy即可。int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); 该函数用来创建一个线程。attr是创建线程时使用的各种属性,由pthread_attr_init()设定。当该线程被调度时会从函数start_routine(一段用户态代码)开始执行。arg做为参数被传递给start_routine。start_routine的原型为:void * start_routine(void *arg);如果线程创建成功,返回值0,并且把线程的ID值存放在thread中;当创建不成功时会返回一个错误号:EAGAIN表示系统缺乏足够的资源来创建线程,EINVAL表示attr结构中的属性值非法。当然,也可以用NULL代替attr的初始化,在需要知道attr的信息或者要修改的时候才去用pthread_attr_init函数void pthread_exit(void *value_ptr);将调用该函数的线程销毁。它没有返回值,因为调用它的线程已经销毁,所以返回值没有任何地方可以“返回”。value_ptr是传给父线程的返回值,父线程调用pthread_join()可得到这个值。这是线程主动终止的唯一方式。int pthread_join(pthread_t thread, void **value_ptr);将调用它的线程阻塞,一直等到thread结束为止。其中thread为被等待的线程ID,value_ptr会接收到被等待线程通过pthread_exit()设置的返回值。

具体相信内容以及其他更多函数请看POSIX Threads Programming


然后开始讲解代码,如果没看过前面几篇文章,建议去看下,因为下面的代码就是修改之前的之后提出来讲的:

1.必不可少的头文件

#include <pthread.h>

2.一些结构以及定义

#define THREAD_NUM 4typedef struct{    int start;    int end;    pthread_t ppid;    pthread_attr_t attr_t;}task_struct;task_struct tasks[THREAD_NUM];

3.将原来的drawPic函数拆分:

void* draw_task(void* arg){double deltaX = (XMax - XMin) / width;double deltaY = (YMax - YMin) / height;//int max_iterations = 256;double max_size = 4.0;        task_struct* t = (task_struct*)arg;for(int row = t->start;row < t->end;row++){for(int col = 0;col < width;col++){int color = 0;Complex c,z;z.real = 0;z.img = 0;c.real  = XMin + col * deltaX;c.img = YMin + row * deltaY;//z.real = XMin + col * deltaX;//z.img = YMin + row * deltaY;//c.real = 0.285;//c.img = 0.01;while((color < MAX_COLOR) && ((z.img * z.img + z.real * z.real) < max_size)){double tmp = z.real * z.real - z.img * z.img + c.real;z.img = z.img * z.real * 2 + c.img;z.real = tmp;color++;}if(color == MAX_COLOR)            {                IMG_8UB(fractal,col,row) = 0;    IMG_8UG(fractal,col,row) = 0;    IMG_8UR(fractal,col,row) = 0;            }            else            {                IMG_8UB(fractal,col,row) = B[color];     IMG_8UG(fractal,col,row) = G[color];    IMG_8UR(fractal,col,row) = R[color];            }//color %= MAX_COLOR;}}    pthread_attr_destroy(&(t->attr_t));    pthread_exit(NULL);}void drawPic(){    int step = height / THREAD_NUM;    for(int i = 0;i < THREAD_NUM;i++)    {        tasks[i].start = i * step;//分配任务        tasks[i].end = tasks[i].start + step;        if(i == THREAD_NUM - 1)            tasks[i].end += height % THREAD_NUM;        pthread_attr_init(&(tasks[i].attr_t));        if(pthread_create(&(tasks[i].ppid),&(tasks[i].attr_t),draw_task,(void*)&tasks[i]))//开始建立线程            printf("Error create pthread!\n");        }    void* status;    for(int i = 0;i < THREAD_NUM;i++)    {        if(!pthread_join(tasks[i].ppid,&status))//阻塞主线程,等待所有的子线程            printf("Thread %ld,exit with status %d\n",tasks[i].ppid,(int)status);        else            printf("Error when join\n");    }    //cvCvtColor(fractal,fractal,CV_HSV2BGR);    cvSaveImage(name[fileIndex++],fractal);    cvShowImage("Fractal",fractal);    cvCopy(fractal,fcopy);      //cvWaitKey(0);}


然后,编译:对于线程函数,需要加上库-lpthread

g++ main.cpp -o main `pkg-config opencv --libs --cflags opencv` -lpthread



原创粉丝点击