测试处理器的多线程性能

最近学习了linux的多线程,就写了个测试处理器多线程性能的例子,里面用到了 线程,信号量,互斥锁等,写得比较麻烦,呵呵,但是整体思路用来学习还是不错的.里面多由详细的中文注释;

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#include <semaphore.h>
#include <string.h>
#include <sys/wait.h>

#define TEST1_NUM 10000    //第一个测试建立的线程数
#define TEST2_NUM 50000    // ...第二个
#define TEST3_NUM 100000 // ...第三个
#define TEST4_NUM 500000 // ...第四个   这些数值用户可以自行更改

 

struct time_out_struct
{
char *out_str; //退出时的错误提示
int out_time_def;       //用户设置的超时时间
int out_time_temp;      //当前的超时时间
int clock_id;           //超时的ID
int time_out_ison;
}afasfsafsadfsafssadfasdfasfsafsfsfsadfsadfsadflkjflkasjflwjeofpf;

#define MAX_TO_NUM 10

struct public_time_out
{
int max_id;
int count_id;
struct time_out_struct *pt_p[MAX_TO_NUM];       //指向已有超时器的指针
pthread_mutex_t pto_mx; //定时器使用的互斥锁
pthread_t pt_id;
}P_TIMEOUT={0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};

int time_out_check_create(int out_time,char *out_str); //创建超时对象,模式初始化后是关闭的
void * start_to(void * arg);    //超时统计线程
void time_out_public_start();   //开始执行超时统计线程
void watch_dog(int toid);       //喂狗操作
void enable_dog(int toid);      //时能某个超时对象
void disable_dog(int toid);     //关闭某个超时对象

int otid1;      //建立超时对象1
int otid2;
#define ON 1
#define OFF 0

#define JD_DISPLAY ON   //是否显示进度条开关
#if(JD_DISPLAY!=OFF)
#define JD_DISPLAY_ON
#endif

#ifdef JD_DISPLAY_ON

#define DIS_FD 100 //按照100份进行显示,如果显示栏比较窄,这个数字可以改小
void dis_jd(int temp_jd);       //显示进度条
void *display_fun(void *arg);   //显示线程
void once_disstart(void);       //一次执行测试
void add_time(struct timeval begin,struct timeval *sum);
int k_sum=TEST1_NUM+TEST2_NUM+TEST3_NUM+TEST4_NUM;      //需要测试的线程数
int last_jd=0; //已经测试过的线程数的百分比*100
sem_t mysem;    //创建一个信号,用于通知测试数据更新
#endif

int k_count=0; //当前已经测试过的线程数
struct timeval * xntest(int num);       //用于测试

void *thread_fun(void *arg)
{
k_count++;
#ifdef JD_DISPLAY_ON
int temp_jd=(k_count*DIS_FD)/k_sum;
if(temp_jd>last_jd)
{
last_jd=temp_jd;        //更新进度
sem_post(&mysem);               //加信号
}
#endif
pthread_exit(0);
}

struct timeval *t_times_p[4];
int main()
{
float jg[4],jg_sum;
int i,pid;
#ifdef JD_DISPLAY_ON
pthread_t tid_display;
struct timeval *display_time;

pid=fork();
if(pid<0)
{
printf("进程错误!\n");
exit(0);
}
if(pid==0)
{
execlp("clear","clear",NULL);
//执行清屏命令后退出
exit(0);        //这句正常情况下不会被执行到
}

waitpid(pid,NULL,0);    //等待子进程清屏后再执行,否则有可能将父进程的正常输出清空

        //在父进程中
//
//
otid1=time_out_check_create(200,"程序超时(超过200秒)退出! ");    //创建超时对象
otid2 =time_out_check_create(2,"线程建立时间过长,您是否在运行其他消耗资源的程序?");
time_out_public_start();        //开始超时统计线程
enable_dog(otid1);      //使能一个对象
if(sem_init(&mysem,0,0)!=0)     //初始化信号量
{
printf("创建信号错误!\n");
exit(0);
}

        if(pthread_create(&tid_display,NULL,display_fun,NULL)!=0)
{//这个线程用来更新显示进度条
printf("显示线程创建错误!\n");
exit(0);
}
#endif
t_times_p[0]=xntest(TEST1_NUM);
t_times_p[1]=xntest(TEST2_NUM);
t_times_p[2]=xntest(TEST3_NUM);
t_times_p[3]=xntest(TEST4_NUM);

jg[0]=t_times_p[0]->tv_sec+(float)(t_times_p[0]->tv_usec)/1000000;
jg[1]=t_times_p[1]->tv_sec+(float)(t_times_p[1]->tv_usec)/1000000;
jg[2]=t_times_p[2]->tv_sec+(float)(t_times_p[2]->tv_usec)/1000000;
jg[3]=t_times_p[3]->tv_sec+(float)(t_times_p[3]->tv_usec)/1000000;
jg_sum=jg[0]+jg[1]+jg[2]+jg[3];
#ifdef JD_DISPLAY_ON
pthread_join(tid_display,(void*)&display_time);
printf("总花费时间: %f \n",jg_sum);
jg_sum=jg[0]+jg[1]+jg[2]+jg[3]-
(display_time->tv_sec+(float)display_time->tv_usec/1000000);
printf("显示所耗费时间: %f\n实际有效可参考时间:%f\n",
display_time->tv_sec+(float)display_time->tv_usec/1000000,
jg_sum);

#endif
printf("\nStat:\n"); //计算完毕,开始统计

        for(i=0;i<73;i++)       printf("-");
printf("\n|    loop num    |%6d       |%6d       |%6d       |%6d       |\n",
TEST1_NUM,TEST2_NUM     ,TEST3_NUM,TEST4_NUM);
for(i=0;i<73;i++)       printf("-");
printf("\n| sum:%10f |%11fs |%11fs |%11fs |%11fs |\n",
jg_sum,jg[0],jg[1],jg[2],jg[3]
);

        for(i=0;i<73;i++)       printf("-");
printf("\n\n");
exit(0);
}

struct timeval * xntest(int num)
{
pthread_t tid_temp;
pthread_attr_t attr_val;        //建立线程属性
struct sched_param scheduling_val;      //建立线程优先级属性结构体
struct timeval t_start,t_end;
struct timeval *return_timeval=malloc(sizeof(struct timeval));
int res,i_loop_test;

        enable_dog(otid2);
pthread_attr_init(&attr_val);   //初始化线程属性,都是默认值
gettimeofday(&t_start,NULL);

        scheduling_val.sched_priority=99;       //设置测试线程的优先级为最高
pthread_attr_setschedparam(&attr_val,&scheduling_val); //添加优先级属性
for(i_loop_test=0;i_loop_test<num;i_loop_test++)
{
watch_dog(otid2);//喂狗操作
res=pthread_create(&tid_temp,&attr_val,thread_fun,NULL);
if(res!=0)
{
printf("测试出错,建立线程出错\n,错误在第 %d 次\n",i_loop_test);
exit(0);
}
res=pthread_join(tid_temp,NULL);
if(res!=0)
{
printf("测试出错,删除线程出错\n,错误在第 %d 次\n",i_loop_test);
}
}
disable_dog(otid2);
gettimeofday(&t_end,NULL);

        return_timeval->tv_usec=t_end.tv_usec-t_start.tv_usec;
return_timeval->tv_sec=t_end.tv_sec-t_start.tv_sec;
if(return_timeval->tv_usec<0)
{
return_timeval->tv_usec+=1000000;
return_timeval->tv_sec--;
}
#ifdef JD_DISPLAY_ON
sleep(1);
printf(" N=%d T=%fs\n",
num,return_timeval->tv_sec+(float)return_timeval->tv_usec/1000000);
#endif
pthread_attr_destroy(&attr_val);        //删除属性空间

        return return_timeval;
}

#ifdef JD_DISPLAY_ON
void *display_fun(void *arg)
{
static pthread_once_t myonce=PTHREAD_ONCE_INIT;
pthread_once(&myonce,once_disstart);    //只用来执行一次
struct timeval t_start,* return_time;
return_time=malloc(sizeof(struct timeval));
memset(return_time,0x00,sizeof(struct timeval));
while(1)
{
sem_wait(&mysem);       //如果没有更新到1%的进度,则堵塞
gettimeofday(&t_start,NULL); //记录开始显示时间
dis_jd(last_jd);
if(last_jd==DIS_FD)
{      
pthread_exit(return_time);
}
//      gettimeofday(&t_end,NULL);      //记录显示结束时间
add_time(t_start,return_time);
}
}

void add_time(struct timeval begin,struct timeval *sum)
{
struct timeval temp_add,end;
gettimeofday(&end,NULL);
temp_add.tv_usec=end.tv_usec-begin.tv_usec;
temp_add.tv_sec=end.tv_sec-begin.tv_sec;
if(temp_add.tv_usec<0)
{
temp_add.tv_usec+=1000;
temp_add.tv_sec--;
}

sum->tv_usec+=temp_add.tv_usec;
sum->tv_sec+=temp_add.tv_sec;
if(sum->tv_usec>1000000)
{
sum->tv_usec-=1000000;
sum->tv_sec++;
}
}

void once_disstart(void)
{
printf("\n\n\n ======================start thread testing======================\n\n");
}

void dis_jd(int temp_jd)
{
static int dis_jd=0;
int i=0;
for(i=0;i<temp_jd-dis_jd;i++)
{
printf("#");
fflush(stdout);
}
dis_jd=temp_jd;
}

#endif

int time_out_check_create(int out_time,char *out_str)   //程序超时锁创建(超时时间,退出时提示信息)
{//返回-1为错误,否则是锁ID
if(P_TIMEOUT.count_id+1>MAX_TO_NUM) return -1; //超时器满了
struct time_out_struct *temp_to=malloc(sizeof(struct time_out_struct));
temp_to->out_str=out_str;
temp_to->out_time_def=out_time;
temp_to->out_time_temp=out_time;
temp_to->clock_id=P_TIMEOUT.max_id;
temp_to->time_out_ison=0;
P_TIMEOUT.pt_p[temp_to->clock_id]=temp_to;     
P_TIMEOUT.count_id++;
P_TIMEOUT.max_id++;
//              printf("time_out_check_create函数\n");

        return temp_to->clock_id; //返回注册的号码
}

void time_out_public_start()
{
//              sleep(1);
pthread_mutex_init(&P_TIMEOUT.pto_mx,NULL);     //创建快速互斥锁
pthread_create(&P_TIMEOUT.pt_id,NULL,start_to,NULL);    //开始统计线程

//              printf("time_tou_public_start_dog函数\n");
}

void * start_to(void * arg)
{
int i;
pthread_cleanup_push((void *)pthread_mutex_unlock,&(P_TIMEOUT.pto_mx)); //压入退出需要执行的函数
while(1)
{
pthread_mutex_lock(&(P_TIMEOUT.pto_mx));        //得到锁子
for(i=0;i<P_TIMEOUT.count_id;i++)
{
if(P_TIMEOUT.pt_p[i]->time_out_ison==0)
{              

continue;       //如果功能未打开,直接跳过
}
P_TIMEOUT.pt_p[i]->out_time_temp--;
if((P_TIMEOUT.pt_p[i])->out_time_temp<0)
{
printf("%s\n",P_TIMEOUT.pt_p[i]->out_str);
exit(0);        //退出整个进程
}

                }

                pthread_mutex_unlock(&(P_TIMEOUT.pto_mx));
sleep(1);
}
pthread_cleanup_pop(0);
}

void watch_dog(int toid)        //喂狗操作
{

        if(pthread_mutex_trylock(&P_TIMEOUT.pto_mx)==0)
{//尝试获得互斥锁,如果得到,则改变数值
P_TIMEOUT.pt_p[toid]->out_time_temp=P_TIMEOUT.pt_p[toid]->out_time_def;
pthread_mutex_unlock(&P_TIMEOUT.pto_mx);        //解开互斥锁
}
}

void enable_dog(int toid)
{
P_TIMEOUT.pt_p[toid]->time_out_ison=1;
}
void disable_dog(int toid)
{
P_TIMEOUT.pt_p[toid]->time_out_ison=0;
}

/********************************************************
该程序使用 gcc -o xntest xntest.c -lpthread 编译
加-lpthread的原因是 在linux中 多线程所使用的都是外部库,内核本身是没有的,好像在内部实现的方法
和进程差不多,都是使用 _clone()实现的, 目前linux多线程的外部库有两种 第一个就是 pthraed,第二种是
NTPL,NTPL是比较新的,性能要比传统的pthread高很多,大家也可以使用nptl的方式进行编译和运行,顺便留言告诉我你的成绩 ,我的总成绩是50多秒....慢啊.
********************************************************/

原文链接: https://www.cnblogs.com/flyxiang2010/archive/2010/12/17/1909038.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    测试处理器的多线程性能

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/18922

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月7日 下午7:51
下一篇 2023年2月7日 下午7:52

相关推荐