初学操作系统对于线程的知识了解是很重要的,因此我们借用对pthread库函数的一些小运用来加深对多线程的认识。
注:本实验在linux系统下进行。
“pthread.h”头文件无法在windows平台下直接引用,需要在编译器编译过程中自行添加,笔者测试用的是pthreads-w32-2-4-0-release.exe,有兴趣的读者可自行研究这里不作扩展。
涉及到的函数有:
pthread_create //用于创建一个新的线程
//pthread_create函数原型:
#include <pthread.h>
int pthread_create(pthread_t *restrict tidp,
const pthread_attr_t *restrict attr,
void *(*start_rtn)(void),
void *restrict arg);
Returns: 0 if OK, error number on failure
- pthread_t *restrict tidp ,tidp是指向一个线程ID的指针。
- const pthread_attr_t *restrict attr:线程属性设置。
- void *(*start_rtn)(void),第三个参数是一个指向函数指针,即线程运行函数的起始地址。新创建的线程从该函数的起始地址开始运行。
- void *restrict arg:给执行函数传递参数参数
返回值:
若成功则返回0,否则返回出错编号。
由 restrict修饰的指针是最初唯一对指针所指向的对象进行存取的方法,所有修改该指针所指向内存中内容的操作都必须通过该指针来修改,而不能通过其它途径(其它变量或指针)来修改,保证了代码的安全性。
pthread_jion//阻塞,等待线程结束
//pthread_jion函数原型
#include <pthread.h>
int pthread_join(pthread_t thread,
void **retval);
Returns: 0 if OK, error number on failure
-pthread_t thread:线程ID。
-void **retval为一个用户定义的指针,它可以用来存储被等待线程的返回值。
返回值:
若成功则返回0,否则返回出错编号。
当我们需要所有线程都结束之后再对他们的结果进行统一操作时,就需要在主函数里加入阻塞函数,等待所有线程都结束后在进行后续操作。
实例:随机生成10万个浮点数,创建4个线程分别实现2.5万个浮点数之和最后完成10万个浮点数之和。比较多线程和单线程的计算时间。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <memory.h>
#include <sys/time.h>
#define Max_Set 100000
float ssum[Max_Set];
pthread_t thread[4];
float suma=0.0;
float sumb=0.0;
float sumc=0.0;
float sumd=0.0;
float sum=0.0;
void fullssum(float a[],int length)
{
for(int i=0;i<length;i++)
ssum[i]=rand()/(float)(RAND_MAX/10);
}
void *thread_a(void *in)
{
printf("i am thread_a\n");
for(int i=0;i<Max_Set/4;i++)
{
suma+=ssum[i];
}
printf("suma=====%f\n",suma);
pthread_exit((void *)0);
}
void *thread_b(void *in)
{
printf("i am thread_b\n");
for(int i=Max_Set/4;i<Max_Set/2;i++)
{
sumb+=ssum[i];
}
printf("sumb=====%f\n",sumb);
pthread_exit((void *)0);
}
void *thread_c(void *in)
{
printf("i am thread_c\n");
for(int i=Max_Set/2;i<Max_Set*3/4;i++)
{
sumc+=ssum[i];
}
printf("sumc=====%f\n",sumc);
pthread_exit((void *)0);
}
void *thread_d(void *in)
{
printf("i am thread_d\n");
for(int i=Max_Set*3/4;i<Max_Set;i++)
{
sumd+=ssum[i];
}
printf("sumd=====%f\n",sumd);
pthread_exit((void *)0);
}
int main()
{
int temp;
struct timeval start, end1,end2;
//用随机数填满数组
fullssum(ssum,Max_Set);
//初始化线程ID
memset(&thread ,0 ,sizeof(thread));
//获取当前时间
gettimeofday(&start,NULL);
if((temp=pthread_create(&thread[0],NULL,thread_a,NULL))!=0)
printf("error in thread_a\n");
else
printf("thread_a creat success!\n");
if((temp=pthread_create(&thread[1],NULL,thread_b,NULL))!=0)
printf("error in thread_b\n");
else
printf("thread_b creat success!\n");
if((temp=pthread_create(&thread[2],NULL,thread_c,NULL))!=0)
printf("error in thread_c\n");
else
printf("thread_c creat success!\n");
if((temp=pthread_create(&thread[3],NULL,thread_d,NULL))!=0)
printf("error in thread_d\n");
else
printf("thread_d creat success!\n");
for(int i=0;i<4;i++)
{
if(thread[0]!=0)
{
pthread_join(thread[0],NULL);
printf("thread%d come to an end\n",i+1);
}
}
//等待所有线程结束计算和
printf("RESULT1=======%f\n",suma+sumb+sumc+sumd);
//获取当前时间
gettimeofday(&end1,NULL);
int time1=1000000*(end1.tv_sec-start.tv_sec)+end1.tv_usec-start.tv_usec;
//输出多线程计算用时
printf("time1======%d\n",time1);
for(int j=0;j<Max_Set;j++)
{
sum+=ssum[j];
}
printf("RESULT2=======%f\n",sum);
gettimeofday(&end2,NULL);
int time2=1000000*(end2.tv_sec-end1.tv_sec)+end2.tv_usec-end1.tv_usec;
//输出单线程计算用时
printf("time2======%d\n",time2);
}
使用gcc编译pthread库程序需要加 -lpthread
例如:gcc pthread.c -o thread -lpthread