Linux下用线程pthread加速程序

自从上次写了数学之美之分形——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 4
typedef 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



你可能感兴趣的:(JOIN,thread,编程,linux,struct,null)