原子操作的一段代码学到的知识

本实例是我在学习原子操作看到一段很有趣的程序,包含的知识很多。

首先上程序:

[cpp]  view plain  copy
  1. // test_atomic.cpp : 定义控制台应用程序的入口点。  
  2. //  
  3.   
  4. #define _GNU_SOURCE  
  5. #include <stdio.h>  
  6. #include <pthread.h>  
  7. #include <unistd.h>  
  8. #include <stdlib.h>  
  9. #include <sched.h>  
  10. #include <linux/unistd.h>  
  11. #include <sys/syscall.h>  
  12. #include <errno.h>  
  13. #include<linux/types.h>  
  14. #include<time.h>  
  15. #include <sys/time.h>  
  16. #define INC_TO 1000000 // one million...  
  17. __u64 rdtsc()  
  18. {  
  19.     __u32 lo,hi;  
  20.     __asm__ __volatile__  
  21.         (  
  22.         "rdtsc":"=a"(lo),"=d"(hi)  
  23.         );  
  24.     return (__u64)hi<<32|lo;  
  25. }  
  26.   
  27. int global_int = 0;  
  28. pthread_mutex_t count_lock = PTHREAD_MUTEX_INITIALIZER;  
  29.   
  30. pid_t gettid( void )  
  31. {  
  32.     return syscall( __NR_gettid );  
  33. }  
  34. void *thread_routine( void *arg )  
  35. {  
  36.     int i;  
  37.     int proc_num = (int)(long)arg;  
  38.     __u64 begin, end;  
  39.     struct timeval tv_begin,tv_end;  
  40.     __u64 timeinterval;  
  41.     cpu_set_t set;  
  42.     CPU_ZERO( &set );  
  43.     CPU_SET( proc_num, &set );  
  44.     if (sched_setaffinity( gettid(), sizeof( cpu_set_t ), &set ))  
  45.     {  
  46.         perror( "sched_setaffinity" );  
  47.         return NULL;  
  48.     }  
  49.     begin = rdtsc();  
  50.     gettimeofday(&tv_begin,NULL);  
  51.     for (i = 0; i < INC_TO; i++)  
  52.     {  
  53.         //     global_int++;  
  54.         __sync_fetch_and_add( &global_int, 1 );  
  55.     }  
  56.     gettimeofday(&tv_end,NULL);  
  57.     end = rdtsc();  
  58.     timeinterval =(tv_end.tv_sec - tv_begin.tv_sec)*1000000+(tv_end.tv_usec - tv_begin.tv_usec);  
  59.     fprintf(stderr,"proc_num :%d,__sync_fetch_and_add cost %llu CPU cycle,cost %llu us\n",  proc_num,end-begin,timeinterval);  
  60.     return NULL;  
  61. }  
  62.   
  63. void *thread_routine2( void *arg )  
  64. {  
  65.     int i;  
  66.     int proc_num = (int)(long)arg;  
  67.     __u64 begin, end;  
  68.     struct timeval tv_begin,tv_end;  
  69.     __u64 timeinterval;  
  70.     cpu_set_t set;  
  71.     CPU_ZERO( &set );  
  72.     CPU_SET( proc_num, &set );  
  73.     if (sched_setaffinity( gettid(), sizeof( cpu_set_t ), &set ))  
  74.     {  
  75.         perror( "sched_setaffinity" );  
  76.         return NULL;  
  77.     }  
  78.   
  79.     begin = rdtsc();  
  80.     gettimeofday(&tv_begin,NULL);  
  81.     for(i = 0;i<INC_TO;i++)  
  82.     {  
  83.         pthread_mutex_lock(&count_lock);  
  84.         global_int++;  
  85.         pthread_mutex_unlock(&count_lock);  
  86.     }  
  87.     gettimeofday(&tv_end,NULL);  
  88.     end = rdtsc();  
  89.   
  90.     timeinterval =(tv_end.tv_sec - tv_begin.tv_sec)*1000000                   +(tv_end.tv_usec - tv_begin.tv_usec);  
  91.     fprintf(stderr,"proc_num :%d,pthread lock cost %llu CPU                    cycle,cost %llu us\n",proc_num,end-begin                    ,timeinterval);  
  92.   
  93.     return NULL;  
  94. }  
  95. int main()  
  96. {  
  97.     int procs = 0;  
  98.     int i;  
  99.     pthread_t *thrs;  
  100.     // Getting number of CPUs  
  101.     procs = (int)sysconf( _SC_NPROCESSORS_ONLN );  
  102.     if (procs < 0)  
  103.     {  
  104.         perror( "sysconf" );  
  105.         return -1;  
  106.     }  
  107.     thrs =(pthread_t *) malloc( sizeof( pthread_t ) * procs );  
  108.     if (thrs == NULL)  
  109.     {  
  110.         perror( "malloc" );  
  111.         return -1;  
  112.     }  
  113.     printf( "Starting %d threads...\n", procs );  
  114.     for (i = 0; i < procs; i++)  
  115.     {  
  116.         if (pthread_create( &thrs[i], NULL, thread_routine2,  
  117.             (void *)(long)i ))  
  118.         {  
  119.             perror( "pthread_create" );  
  120.             procs = i;  
  121.             break;  
  122.         }  
  123.     }  
  124.     for (i = 0; i < procs; i++)  
  125.         pthread_join( thrs[i], NULL );  
  126.     free( thrs );  
  127.     printf( "After doing all the math, global_int value is:              %d\n", global_int );  
  128.     printf( "Expected value is: %d\n", INC_TO * procs );  
  129.     return 0;  
  130. }  


该段程序主要是了测试互斥量和原子操作对全局变量的自增,对系统性能的影响。

指标:通过cpu操作计数和时间

[html]  view plain  copy
  1. [root@10-4-23-15 wcl]# ./test_atomic   
  2. Starting 2 threads...  
  3. proc_num :1,__sync_fetch_and_add cost             184322840 CPU cycle,cost 70891 us  
  4. proc_num :0,__sync_fetch_and_add cost             198164962 CPU cycle,cost 76216 us  
  5. After doing all the math, global_int value is:              2000000  
  6. Expected value is: 2000000  

2、操作完对全局的自增后,所需要的时间


对全局操作,一个cpu内核,绑定一个线程,对全局变量操作。

其中一个方法使用

[cpp]  view plain  copy
  1. __sync_fetch_and_add的原子操作,两一个使用的是互斥变量进行全局家。  

[cpp]  view plain  copy
  1. cpu_set_t set;  
  2.     CPU_ZERO( &set );  
  3.     CPU_SET( proc_num, &set );  

设置线程的cpu掩码。将线程一一对应到cpu的核数上,

[cpp]  view plain  copy
  1. sched_setaffinity  
是线程贴合到具体cpu核上。


如何获取cpu核心数:

[cpp]  view plain  copy
  1. procs = (int)sysconf( _SC_NPROCESSORS_ONLN );  

几个cpu核启动几个线程。并一一对应绑定。


获取线程ID:

[cpp]  view plain  copy
  1. syscall( __NR_gettid );  

所以,最终sched_setaffinity 绑定到具体线程上。



测试结果:


[html]  view plain  copy
  1. [root@10-4-23-15 wcl]# ./test_atomic   
  2. Starting 2 threads...  
  3. proc_num :1,__sync_fetch_and_add cost             184322840 CPU cycle,cost 70891 us  
  4. proc_num :0,__sync_fetch_and_add cost             198164962 CPU cycle,cost 76216 us  
  5. After doing all the math, global_int value is:              2000000  
  6. Expected value is: 2000000  


[html]  view plain  copy
  1. [root@10-4-23-15 wcl]# ./test_atomic   
  2. Starting 2 threads...  
  3. proc_num :0,pthread lock cost 492937699 CPU                    cycle,cost 189598 us  
  4. proc_num :1,pthread lock cost 494258362 CPU                    cycle,cost 190106 us  
  5. After doing all the math, global_int value is:              2000000  
  6. Expected value is: 2000000  



通过测试结果,我们可以看到,互斥量消耗的性能是原子操作的三四倍左右。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值