首页 > 技术文章 > 计时功能源码(C/C++,多线程安全)

prophet-ss 2018-02-27 22:35 原文

  这个是接我之前写的C日志代码(http://www.cnblogs.com/prophet-ss/p/8025825.html)的一个功能函数,这里单独拿出来说下。下面这个代码是之前写的,在windows/linux可以通用。最新linux下增加了一个单线程下可以去除锁的控制宏,一个rdtsc汇编指令宏可以获取程序运行时钟周期(比一般类似clock()函数快至少一个数量级)。如有需要可以在上面链接内取(time.c和time.h)。

  简单说下设计思想,首先这里用的是临界区而不是互斥锁,主要因为临界区操作更快对计时影响小。另外一个问题就是计时器数组初始化问题,如何保证多个线程同时运行只初始化一次,这块我使用InterlockedIncrement原子加简单的解决了这一问题。由于注释写的已经很详细,具体接口功能就不再赘述,下面直接上源码:

 1 #ifndef _PRO_TIME_H_
 2 #define _PRO_TIME_H_
 3 
 4 /* 计时器可使用最大个数 */
 5 #define TIMEKEEPER_NUM    100
 6 
 7 #ifdef __cplusplus
 8 extern "C" {
 9 #endif
10 
11 /* 手动计时器设置n - [0,TIMEKEEPER_NUM-1] */
12 int timekeeper_start_man(int n);
13 
14 /* 自动选取一个空闲计时器,返回值(>0)为输入thnd */
15 int timekeeper_start_auto();
16 
17 /* 获取时间,若手动设置thnd为输入参数n,若自动设置则为
18 ** 其返回值(>0。time为输出参数为距上次经过时间,单位s */
19 int timekeeper_pause(int thnd, double* time);
20 
21 /* 获取时间,与pause不同的是获取完会清除释放计时
22 ** 器,下次无法使用 */
23 int timekeeper_shutoff(int thnd, double* time);
24 
25 /* 全部销毁,谨慎使用 */
26 void timekeeper_destory();
27 
28 #ifdef __cplusplus
29 }
30 #endif
31 
32 #endif    /* !_PRO_TIME_H_ */
  1 #include <time.h>
  2 #if defined(_WIN32) || defined(_WIN64)
  3 #include <Windows.h>
  4 #else
  5 #include <pthread.h>
  6 #include <unistd.h>
  7 #endif    /* _WIN32 || _WIN64 */
  8 #include <string.h>
  9 #include "pro_time.h"
 10 
 11 struct safe_timespec
 12 {
 13     struct timespec spec;
 14     /* 0-未被使用,1-已被占用 */
 15     long is_ref;
 16 };
 17 
 18 #define NSEC_PER_SEC    1000000000
 19 
 20 /*计时器临界区*/
 21 #if defined(_WIN32) || defined(_WIN64)
 22 #define sleep(x)    Sleep(x)
 23 static CRITICAL_SECTION _timekeeper_mutex;
 24 #else
 25 #define atomic_inc(x) __sync_add_and_fetch((x),1)
 26 static pthread_mutex_t _timekeeper_mutex = PTHREAD_MUTEX_INITIALIZER;
 27 #endif    /* _WIN32 || _WIN64 */
 28 
 29 
 30 /*计时器数组*/
 31 static struct safe_timespec _ptimekeeper[TIMEKEEPER_NUM] = { 0 };
 32 
 33 /* 多线程初始化标记,防止多次初始化 */
 34 static volatile long _timekeeper_sync = 0;
 35 
 36 /* 初始化标志 */
 37 static volatile int _is_initialized = 0;
 38 
 39 static void _timekeeper_initialize(void)
 40 {
 41     if (!_is_initialized)
 42     {
 43         /* 原子操作加1,如果结果为1当前只有本线程调用可以初始化,不为1(>1)
 44         ** 说明有其他线程调用等待其他线程初始化完毕即可 */
 45     #if defined(_WIN32) || defined(_WIN64)
 46         if (InterlockedIncrement(&_timekeeper_sync) == 1)
 47     #else
 48         if (atomic_inc(&_timekeeper_sync) == 1)
 49     #endif    /* _WIN32 || _WIN64 */
 50         {
 51             /* 初始化 */
 52         #if defined(_WIN32) || defined(_WIN64)
 53             InitializeCriticalSection(&_timekeeper_mutex);
 54         #endif    /* _WIN32 || _WIN64 */
 55             memset(_ptimekeeper, 0, TIMEKEEPER_NUM * sizeof(struct safe_timespec));
 56             _is_initialized = 1;
 57         }
 58         else
 59         {
 60             /* 等待其他线程初始化完毕 */
 61             while (!_is_initialized) sleep(0);
 62         }
 63     }
 64 }
 65 
 66 static void _timekeeper_lock(void)
 67 {
 68     _timekeeper_initialize();
 69 
 70 #if defined(_WIN32) || defined(_WIN64)
 71     EnterCriticalSection(&_timekeeper_mutex);
 72 #else
 73     pthread_mutex_lock(&_timekeeper_mutex);
 74 #endif    /* _WIN32 || _WIN64 */
 75     
 76 }
 77 
 78 static void _timekeeper_unlock(void)
 79 {
 80 #if defined(_WIN32) || defined(_WIN64)
 81     LeaveCriticalSection(&_timekeeper_mutex);
 82 #else
 83     pthread_mutex_unlock(&_timekeeper_mutex);
 84 #endif    /* _WIN32 || _WIN64 */
 85 }
 86 
 87 static int _timekeeper_get(int n)
 88 {
 89     _timekeeper_lock();
 90 
 91     if (_ptimekeeper[n].is_ref != 0)
 92     {
 93         _timekeeper_unlock();
 94         return -2;
 95     }
 96     timespec_get(&(_ptimekeeper[n].spec), TIME_UTC);
 97     _ptimekeeper[n].is_ref = 1;
 98 
 99     _timekeeper_unlock();
100     return 0;
101 }
102 
103 int timekeeper_start_man(int n)
104 {
105     return _timekeeper_get(n);
106 }
107 
108 int timekeeper_start_auto()
109 {
110     for (int i = 0; i < TIMEKEEPER_NUM; i++)
111     {
112         if (0 == _timekeeper_get(i))
113             return i;
114     }
115     return -1;
116 }
117 
118 int timekeeper_pause(int thnd, double* time)
119 {
120     struct timespec tk;
121     if (timespec_get(&tk, TIME_UTC) != 0)
122         *time = tk.tv_sec - (_ptimekeeper[thnd].spec).tv_sec +
123         (double)(tk.tv_nsec - (_ptimekeeper[thnd].spec).tv_nsec) / NSEC_PER_SEC;
124     else
125         return -4;
126 
127     return 0;
128 }
129 
130 int timekeeper_shutoff(int thnd, double* time)
131 {
132     int ret;
133     if ((ret = timekeeper_pause(thnd, time)) != 0)
134         return ret;
135 
136     _timekeeper_lock();
137     _ptimekeeper[thnd].is_ref = 0;
138     _timekeeper_unlock();
139 
140     return 0;
141 }
142 
143 void timekeeper_destory()
144 {
145     _timekeeper_lock();
146     _is_initialized = 0;
147     _timekeeper_unlock();
148 }
 1 #if defined(_WIN32) || defined(_WIN64)
 2 #include <Windows.h>
 3 #else
 4 #include <pthread.h>
 5 #endif    /* _WIN32 || _WIN64 */
 6 #include <stdio.h>
 7 #include "pro_time.h"
 8 
 9 
10 void* test(void *arg)
11 {
12     int i;
13     int t = *(int*)arg;
14     for (i = 0; i < 11; i++)
15     {
16         int n = timekeeper_start_auto();
17         printf("thread%d,i=%d,", t, n);
18         double tm;
19         timekeeper_pause(n, &tm);
20         printf("%f\n", tm);
21     }
22 }        
23 
24 int main()
25 {
26     pthread_t tpid[10];
27     int i;
28     for (i = 0; i < 10; i++)
29     {
30     #if defined(_WIN32) || defined(_WIN64)
31         _beginthread(fun, 0, &i);
32     #else
33         pthread_create(&tpid[i], NULL, &test, &i);
34     #endif    /* _WIN32 || _WIN64 */
35     }
36 }

 

=======================================================================================

2018-03-11 23:40:53更新:增加linux和C++的使用

=======================================================================================

2018-07-03 21:26:34更新:linux添加rdtsc指令宏和多线程控制宏

推荐阅读