1. 程式人生 > >執行緒一寫多讀的實驗

執行緒一寫多讀的實驗

前言

demo中,一個執行緒在寫計數++, 另外一個執行緒在讀, 算出tps。遇到了tps算不準的問題。 後來發現是分母上的時間差用秒為單位的緣故(1.5秒和2.4秒用2個time(NULL)減之後都是2秒)。換成微秒時間再乘以1000000就正常了。 開始一度想使用__sync_xx系列函式讀取計數時,都同步一下。被同事指出這是在迴避問題,尷尬… 其實,有問題時,各種實驗都嘗試一下。通過實驗定位問題後,再解決就容易了。就像本次遇到的tps算不準的問題,如果嘗試了__sync_xx後,肯定還是tps不準。那我就嘗試下一個實驗方法,這被扣上回避問題的帽子,也是真尷尬。只能說,如果開始嘗試解決問題的方法對路,實驗少做一些而已。

寫了一個demo, 驗證"一寫多讀"。實驗證明,多個執行緒讀值時,讀到的都是寫執行緒寫的值,不會讀到亂的值。

做這個實驗,對linux執行緒的用法(傳執行緒上下文, 執行緒啟動,使用執行緒上下文,執行緒停止)複習了一次。使用linux執行緒時,設定執行緒上下文退出標記,讓執行緒檢測到退出標記後,自己退出。

demo下載點

稍後上傳

執行效果

Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.124 : remove_file()] : failed : remove [/var/log/test_time__file_flag_to_shutdown], error[-1] = [No such file or directory]
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.124 : remove_file()] : failed : remove [/var/log/test_time__file_flag_to_thread_run_all], error[-1] = [No such file or directory]
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.124 : remove_file()] : failed : remove [/var/log/test_time__file_flag_to_debug], error[-1] = [No such file or directory]
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.102 : main()] : MAKE_FILE_MACRO__BIN_NAME = [test_time]
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.460 : fn_test()] : >> fn_test()
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.462 : fn_test()] : l_cpu_numbers = 16
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.465 : fn_test()] : l_thread_numbers = 32
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[0] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[1] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[2] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[3] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.348 : thread_proc_write()] : >> thread_proc_write[0]
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[1], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[2], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[4] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[5] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[3], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[6] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[7] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[5], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[8] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[6], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[9] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[7], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[10] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[4], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[11], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[8], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[10], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[11] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[9], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[12] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[12], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[13] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[13], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[14] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[14], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[15] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[15], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[16] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[16], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[17] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[17], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[18], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[18] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[19] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[19], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[20] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[20], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[21] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[21], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[22], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[22] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[23] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[23], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[24], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[24] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[25] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[25], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[26] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[26], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[27] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[27], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[28] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[28], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[29] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[29], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[30] create
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.396 : thread_proc_read()] : >> thread_proc_read[30], wait FILE_FLAG_THREAD_RUN_ALL
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.280 : thread_proc_env_check()] : >> thread_proc_env_check[31]
Oct 16 06:02:59 debian8 test_time: [MY_LOGD : main.cpp.507 : fn_test()] : ok : pthread[31] create

...

Oct 16 06:03:58 debian8 test_time: [MY_LOGD : main.cpp.401 : thread_proc_read()] : >> thread_proc_read[5] find FILE_FLAG_THREAD_RUN_ALL, will be run
Oct 16 06:03:58 debian8 test_time: [MY_LOGD : main.cpp.353 : thread_proc_write()] : >> thread_proc_write[0] find FILE_FLAG_THREAD_RUN_ALL, will be run
Oct 16 06:03:58 debian8 test_time: [MY_LOGD : main.cpp.401 : thread_proc_read()] : >> thread_proc_read[10] find FILE_FLAG_THREAD_RUN_ALL, will be run
Oct 16 06:03:58 debian8 test_time: [MY_LOGD : main.cpp.401 : thread_proc_read()] : >> thread_proc_read[8] find FILE_FLAG_THREAD_RUN_ALL, will be run
Oct 16 06:03:58 debian8 test_time: [MY_LOGD : main.cpp.401 : thread_proc_read()] : >> thread_proc_read[13] find FILE_FLAG_THREAD_RUN_ALL, will be run
Oct 16 06:03:58 debian8 test_time: [MY_LOGD : main.cpp.401 : thread_proc_read()] : >> thread_proc_read[2] find FILE_FLAG_THREAD_RUN_ALL, will be run
Oct 16 06:03:58 debian8 test_time: [MY_LOGD : main.cpp.401 : thread_proc_read()] : >> thread_proc_read[1] find FILE_FLAG_THREAD_RUN_ALL, will be run
Oct 16 06:03:58 debian8 test_time: [MY_LOGD : main.cpp.401 : thread_proc_read()] : >> thread_proc_read[6] find FILE_FLAG_THREAD_RUN_ALL, will be run
Oct 16 06:03:58 debian8 test_time: [MY_LOGD : main.cpp.401 : thread_proc_read()] : >> thread_proc_read[9] find FILE_FLAG_THREAD_RUN_ALL, will be run
Oct 16 06:03:58 debian8 test_time: [MY_LOGD : main.cpp.401 : thread_proc_read()] : >> thread_proc_read[16] find FILE_FLAG_THREAD_RUN_ALL, will be run
Oct 16 06:03:58 debian8 test_time: [MY_LOGD : main.cpp.401 : thread_proc_read()] : >> thread_proc_read[4] find FILE_FLAG_THREAD_RUN_ALL, will be run
Oct 16 06:03:58 debian8 test_time: [MY_LOGD : main.cpp.401 : thread_proc_read()] : >> thread_proc_read[20] find FILE_FLAG_THREAD_RUN_ALL, will be run

...

Oct 16 06:05:50 debian8 test_time: [MY_LOGD : main.cpp.243 : calc_tps_and_show()] : thread[6] tps = 2013, ull_cnt_prev = 217230, ull_time_prev = 1539641149002014
Oct 16 06:05:50 debian8 test_time: [MY_LOGD : main.cpp.243 : calc_tps_and_show()] : thread[19] tps = 2013, ull_cnt_prev = 217231, ull_time_prev = 1539641149002510
Oct 16 06:05:50 debian8 test_time: [MY_LOGD : main.cpp.243 : calc_tps_and_show()] : thread[4] tps = 2014, ull_cnt_prev = 217232, ull_time_prev = 1539641149003070
Oct 16 06:05:50 debian8 test_time: [MY_LOGD : main.cpp.243 : calc_tps_and_show()] : thread[1] tps = 2012, ull_cnt_prev = 217233, ull_time_prev = 1539641149003532
Oct 16 06:05:50 debian8 test_time: [MY_LOGD : main.cpp.243 : calc_tps_and_show()] : thread[24] tps = 2012, ull_cnt_prev = 217233, ull_time_prev = 1539641149003512
Oct 16 06:05:50 debian8 test_time: [MY_LOGD : main.cpp.243 : calc_tps_and_show()] : thread[9] tps = 2013, ull_cnt_prev = 217234, ull_time_prev = 1539641149003998
Oct 16 06:05:50 debian8 test_time: [MY_LOGD : main.cpp.243 : calc_tps_and_show()] : thread[17] tps = 2012, ull_cnt_prev = 217236, ull_time_prev = 1539641149004498
Oct 16 06:05:50 debian8 test_time: [MY_LOGD : main.cpp.243 : calc_tps_and_show()] : thread[26] tps = 2013, ull_cnt_prev = 217238, ull_time_prev = 1539641149006115
Oct 16 06:05:50 debian8 test_time: [MY_LOGD : main.cpp.243 : calc_tps_and_show()] : thread[27] tps = 2014, ull_cnt_prev = 217238, ull_time_prev = 1539641149006145
Oct 16 06:05:50 debian8 test_time: [MY_LOGD : main.cpp.243 : calc_tps_and_show()] : thread[14] tps = 2013, ull_cnt_prev = 217239, ull_time_prev = 1539641149006304
Oct 16 06:05:50 debian8 test_time: [MY_LOGD : main.cpp.243 : calc_tps_and_show()] : thread[10] tps = 2013, ull_cnt_prev = 217239, ull_time_prev = 1539641149006256
Oct 16 06:05:50 debian8 test_time: [MY_LOGD : main.cpp.243 : calc_tps_and_show()] : thread[25] tps = 2013, ull_cnt_prev = 217240, ull_time_prev = 1539641149006591

...

Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.286 : thread_proc_env_check()] : thread_proc_env_check[31] recv quit command, stop other thread ...
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[0].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[1].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[2].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[3].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[4].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[5].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[6].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[7].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[8].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[9].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[10].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[11].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[12].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[13].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[14].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.362 : thread_proc_write()] : >> thread_proc_write[0] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.375 : thread_proc_write()] : << thread_proc_write[0]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[15].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[16].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[17].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[18].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[19].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[20].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[21].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[22].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[23].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[24].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[25].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[26].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[27].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[28].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[29].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.300 : thread_proc_env_check()] : set _p_ctx->p_thread_ctx_parent[30].b_request_quit_thread = true
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.313 : thread_proc_env_check()] : >> wait _p_ctx->p_thread_ctx_parent[1].h_thread end
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[11] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[4] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[11]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[4]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[22] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[22]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[12] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[12]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[19] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[19]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[18] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[18]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[9] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[9]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[13] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[13]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[25] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[25]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[21] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[21]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[26] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[26]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[15] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[15]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[10] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[10]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[20] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[20]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[6] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[6]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[16] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[16]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[1] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[1]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[24] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[24]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[23] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[23]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[5] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[5]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[30] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[30]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[29] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[29]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[17] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[17]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[27] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[27]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[2] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[2]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[28] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[28]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[3] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[3]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.315 : thread_proc_env_check()] : << wait _p_ctx->p_thread_ctx_parent[1].h_thread end
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.313 : thread_proc_env_check()] : >> wait _p_ctx->p_thread_ctx_parent[7].h_thread end
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[8] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[8]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[7] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[7]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.418 : thread_proc_read()] : >> thread_proc_read[14] find b_request_quit_thread, will be quit
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.431 : thread_proc_read()] : << thread_proc_read[14]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.315 : thread_proc_env_check()] : << wait _p_ctx->p_thread_ctx_parent[7].h_thread end
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.327 : thread_proc_env_check()] : << thread_proc_env_check[31]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.529 : fn_test()] : ok : stop thread_env_check
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.127 : remove_file()] : ok : remove [/var/log/test_time__file_flag_to_shutdown]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.127 : remove_file()] : ok : remove [/var/log/test_time__file_flag_to_thread_run_all]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.124 : remove_file()] : failed : remove [/var/log/test_time__file_flag_to_debug], error[-1] = [No such file or directory]
Oct 16 06:06:40 debian8 test_time: [MY_LOGD : main.cpp.110 : main()] : THE END


實驗

// @file main.cpp
// @brief 測試時間取值(us)和計數(一寫多讀)
// @note 
// 	實驗環境:
//	debian8.8
//
// 	除錯:
// 	when debug, see log => tail -f /var/log/messages | grep MY_LOGD

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <signal.h>
#include <errno.h>
#include <sys/time.h>
#include <pthread.h>

#include <string>

#include "const_define.h"

// 執行緒自己的私有資料
typedef struct _tag_thread_private_data {
	long l_tps; // 算出的當前tps值
	ull ull_time_prev; // 上一次記錄tps的時間
	ull ull_cnt_prev; // 上一次記錄的計數器值

	_tag_thread_private_data() {
		l_tps = 0;
		ull_time_prev = 0;
		ull_cnt_prev = 0;
	}
}TAG_THREAD_PRIVATE_DATA;

// 執行緒之間共享的資料
typedef struct _tag_thread_share_data {
	ull ull_cnt; // 一寫多讀的計數器

	_tag_thread_share_data() {
		ull_cnt = 0;
	}
}TAG_THREAD_SHARE_DATA;

// 執行緒上下文
typedef struct _tag_thread_context {
	bool b_init_h_thread; // h_thread is init ?
	pthread_t h_thread; // 執行緒控制代碼
	
	int i_thread_sn; // 執行緒號碼

	_tag_thread_context* p_thread_ctx_parent; // 總的執行緒上下文, 用於環境檢測執行緒停止其他執行緒
	long l_thread_numbers; // p_thread_ctx_parent 對應的執行緒數量(p_thread_ctx_parent[]的組數size)
	
	TAG_THREAD_SHARE_DATA* p_share_data; // 執行緒之間共享的資料結構
	TAG_THREAD_PRIVATE_DATA thread_private_data; // 執行緒的私有資料
	bool b_request_quit_thread; // 請求退出執行緒

	_tag_thread_context() {
		// h_thread = NULL; // pthread_t isn't pointer type, can't set to NULL
		b_init_h_thread = false;
		
		i_thread_sn = -1;

		p_thread_ctx_parent = NULL;
		l_thread_numbers = 0;

		p_share_data = NULL;
		b_request_quit_thread = false;
	}
} TAG_THREAD_CONTEXT;

void init(const char* psz_log_owner_name);
void uninit();
void proc_sig_term(int num);
int fn_test(int argc, char** argv);

bool is_file_exist(const char* psz_file_path_name, int& i_err_code, std::string& str_err_msg);
void read_and_show_context(TAG_THREAD_CONTEXT* p_ctx);
void write_and_show_context(TAG_THREAD_CONTEXT* p_ctx);
void show_ull_by_time(const char* psz_tip, ull ull_val);
void calc_tps_and_show(TAG_THREAD_CONTEXT* p_ctx);

void remove_flag_file();
void remove_file(const char* psz_file_path_name);

typedef void* (*PFN_thread_proc_env_check)(void* p_ctx);

void* thread_proc_env_check(void* p_ctx);
void* thread_proc_write(void* p_ctx);
void* thread_proc_read(void* p_ctx);

int main(int argc, char** argv)
{
    char sz_buf[MAX_MSG_LENGTH] = {'\0'};

#ifdef MAKE_FILE_MACRO__BIN_NAME
    sprintf(sz_buf, "%s", MAKE_FILE_MACRO__BIN_NAME);
    init(sz_buf);
    MYLOG_D("MAKE_FILE_MACRO__BIN_NAME = [%s]\n", MAKE_FILE_MACRO__BIN_NAME);
#else
    init(NULL);
#endif // #ifdef MAKE_FILE_MACRO__BIN_NAME

    fn_test(argc, argv);
    uninit();

    MYLOG_D("THE END\n");
    return EXIT_SUCCESS;
}

void remove_file(const char* psz_file_path_name)
{
	int i_rc = 0;
	
	if (NULL != psz_file_path_name) {
		i_rc = remove(psz_file_path_name);
		if (EOK != i_rc) {
			MYLOG_D("failed : remove [%s], error[%d] = [%s]\n",
				psz_file_path_name, 
				i_rc,
				strerror(errno));
		} else {
			MYLOG_D("ok : remove [%s]\n",
				psz_file_path_name);
		}
	}
}

void remove_flag_file()
{
	remove_file(FILE_FLAG_SHUTDOWN);
	remove_file(FILE_FLAG_THREAD_RUN_ALL);
	remove_file(FILE_FLAG_DEBUG);
}

void uninit()
{
	remove_flag_file();
}

void proc_sig_term(int num)
{
    MYLOG_D("SIGTERM = %d, num = %d\n", SIGTERM, num);
    MYLOG_D("maybe can do some clean task before quit\n");
    exit(1);	
}

void init(const char* psz_log_owner_name)
{
    int i = 0;

	MYLOG_D("%s\n", TITLE_LINE80);
	MYLOG_D("%s %s %s\n", 
		(NULL != psz_log_owner_name) ? psz_log_owner_name : "test_prog", 
		PROG_VER,
		RELEASE_TIME);

	MYLOG_D("%s\n", TITLE_LINE80);

    // daemon(0, 0);

    // clear screen (print 25 empty line)
    for (i = 0; i < 25; i++) {
        MYLOG_D("\n");
    }

    signal(SIGTERM, proc_sig_term);

	remove_flag_file();
}

bool is_file_exist(const char* psz_file_path_name, int& i_err_code, std::string& str_err_msg)
{
    bool b_rc = false;
    int i_rc = -1;

    do {
        if ((NULL == psz_file_path_name)
            || (0 == strlen(psz_file_path_name))) {
            i_err_code = -1;
            str_err_msg = "param 1 error";
            break;
        }

        i_rc = access(psz_file_path_name, F_OK);

        if (0 != i_rc) {
            i_err_code = errno;
            str_err_msg = strerror(i_err_code);
        } else {
            b_rc = true;
        }
    } while (0);

    return b_rc;
}

void show_ull_by_time(const char* psz_tip, ull ull_val)
{
	struct timeval tv_now;
	ull ull_time_now = 0;

	gettimeofday(&tv_now, NULL);
	ull_time_now = tv_now.tv_sec;
	ull_time_now *= 1000000;
	ull_time_now += tv_now.tv_usec;

	MYLOG_D("%s : ull_val = %llu, time now = %llu, %ld.%ld\n", 
		(NULL != psz_tip) ? psz_tip : "NULL",
		ull_val, 
		ull_time_now, 
		tv_now.tv_sec, 
		tv_now.tv_usec);
}

void calc_tps_and_show(TAG_THREAD_CONTEXT* p_ctx)
{
	struct timeval tv_now;
	ull ull_time_now = 0;
	ull ull_cnt_val_by_writer = 0;

	if (NULL != p_ctx) {
		gettimeofday(&tv_now, NULL);
		ull_time_now = tv_now.tv_sec;
		ull_time_now *= 1000000;
		ull_time_now += tv_now.tv_usec;

		ull_cnt_val_by_writer = p_ctx->p_thread_ctx_parent->p_share_data->ull_cnt;
		if ((p_ctx->thread_private_data.ull_cnt_prev > 0) 
			&& (p_ctx->thread_private_data.ull_time_prev > 0))
		{
			p_ctx->thread_private_data.l_tps = 
				1.0f * (ull_cnt_val_by_writer - p_ctx->thread_private_data.ull_cnt_prev) 
				/ (ull_time_now - p_ctx->thread_private_data.ull_time_prev) * 1000000;

			MYLOG_D("thread[%d] tps = %ld, ull_cnt_prev = %llu, ull_time_prev = %llu", 
				p_ctx->i_thread_sn, 
				p_ctx->thread_private_data.l_tps,
				p_ctx->thread_private_data.ull_cnt_prev,
				p_ctx->thread_private_data.ull_time_prev);
		}

		p_ctx->thread_private_data.ull_cnt_prev = ull_cnt_val_by_writer;
		p_ctx->thread_private_data.ull_time_prev = ull_time_now;
	}
}

void read_and_show_context(TAG_THREAD_CONTEXT* p_ctx)
{
	TAG_THREAD_CONTEXT* _p_ctx = (TAG_THREAD_CONTEXT*)p_ctx;

	if ((NULL != _p_ctx) && (NULL != _p_ctx->p_share_data)) {
		show_ull_by_time("rd", _p_ctx->p_share_data->ull_cnt);
	}
}

void write_and_show_context(TAG_THREAD_CONTEXT* p_ctx)
{
	TAG_THREAD_CONTEXT* _p_ctx = (TAG_THREAD_CONTEXT*)p_ctx;

	if ((NULL != _p_ctx) && (NULL != _p_ctx->p_share_data)) {
		_p_ctx->p_share_data->ull_cnt++;
		show_ull_by_time("wr", _p_ctx->p_share_data->ull_cnt);
	}
}

void* thread_proc_env_check(void* p_ctx)
{
	TAG_THREAD_CONTEXT* _p_ctx = (TAG_THREAD_CONTEXT*)p_ctx;
	int i = 0;

	do {
		if (NULL == _p_ctx) {
			break;
		}

		MYLOG_D(">> thread_proc_env_check[%d]\n", _p_ctx->i_thread_sn);

		do {
			if (_p_ctx->b_request_quit_thread) {
				// 等主執行緒來停止環境檢測執行緒, 環境檢測執行緒再去停止其他工作執行緒

				MYLOG_D("thread_proc_env_check[%d] recv quit command, stop other thread ...\n", _p_ctx->i_thread_sn);
				
				// close read thread
				// set quit command to all other thread
				for (i = 0; i < _p_ctx->l_thread_numbers; i++) {
					if (_p_ctx->p_thread_ctx_parent[i].i_thread_sn == _p_ctx->i_thread_sn) {
						// 這些執行緒也包含本執行緒, 只處理其他執行緒
						continue;
					}
					
					if (pthread_kill(_p_ctx->p_thread_ctx_parent[i].h_thread, 0) == 0) {
						// if thread is still active, first set thread quit falg
						// thread will quit by p_thread_ctx[i].b_request_quit_thread
						_p_ctx->p_thread_ctx_parent[i].b_request_quit_thread = true;
						MYLOG_D("set _p_ctx->p_thread_ctx_parent[%d].b_request_quit_thread = true\n", i);
					}
				}
				
				// wait all other thread over quit by them slef
				for (i = 0; i < _p_ctx->l_thread_numbers; i++) {
					if (_p_ctx->p_thread_ctx_parent[i].i_thread_sn == _p_ctx->i_thread_sn) {
						// 這些執行緒也包含本執行緒, 只處理其他執行緒
						continue;
					}
				
					if (pthread_kill(_p_ctx->p_thread_ctx_parent[i].h_thread, 0) == 0) {
						// then wait it exit
						MYLOG_D(">> wait _p_ctx->p_thread_ctx_parent[%d].h_thread end\n", i);
						pthread_join(_p_ctx->p_thread_ctx_parent[i].h_thread, NULL);
						MYLOG_D("<< wait _p_ctx->p_thread_ctx_parent[%d].h_thread end\n", i);
					}
				}
				
				break;
			}

			usleep(US_SLEEP_VAL_FO_READER);
		} while (1);
	} while (0);

	if (NULL != _p_ctx) {
		MYLOG_D("<< thread_proc_env_check[%d]\n", _p_ctx->i_thread_sn);
		pthread_exit((void*)(intptr_t)_p_ctx->i_thread_sn);
	} else {
		MYLOG_D("<< thread_proc_env_check\n");
		pthread_exit(NULL);
	}

	return NULL;
}

void* thread_proc_write(void* p_ctx)
{
	TAG_THREAD_CONTEXT* _p_ctx = (TAG_THREAD_CONTEXT*)p_ctx;
	int i_err_code = 0;
	std::string str_err = "";

	do {
		if (NULL == _p_ctx) {
			break;
		}

		MYLOG_D(">> thread_proc_write[%d]\n", _p_ctx->i_thread_sn);

		// wait thread run flag
		do {
			if (is_file_exist(FILE_FLAG_THREAD_RUN_ALL, i_err_code, str_err)) {
				MYLOG_D(">> thread_proc_write[%d] find FILE_FLAG_THREAD_RUN_ALL, will be run\n", _p_ctx->i_thread_sn);
				break;
			}

			usleep(US_SLEEP_VAL_FO_READER);
		} while (1);

		do {
			if (_p_ctx->b_request_quit_thread) {
				MYLOG_D(">> thread_proc_write[%d] find b_request_quit_thread, will be quit\n", _p_ctx->i_thread_sn);
				break;
			}

			// write_and_show_context(_p_ctx);
			_p_ctx->p_thread_ctx_parent->p_share_data->ull_cnt++;
			usleep(US_SLEEP_VAL_FO_WRITER); // 計數增加的頻率遠高於計數讀的頻率
		} while (1);

		
	} while (0);

	if (NULL != _p_ctx) {
		MYLOG_D("<< thread_proc_write[%d]\n", _p_ctx->i_thread_sn);
		pthread_exit((void*)(intptr_t)_p_ctx->i_thread_sn);
	} else {
		MYLOG_D("<< thread_proc_write\n");
		pthread_exit(NULL);
	}

	return NULL;
}

void* thread_proc_read(void* p_ctx)
{
	TAG_THREAD_CONTEXT* _p_ctx = (TAG_THREAD_CONTEXT*)p_ctx;
	int i_err_code = 0;
	std::string str_err = "";
	
	do {
		if (NULL == _p_ctx) {
			break;
		}

		MYLOG_D(">> thread_proc_read[%d], wait FILE_FLAG_THREAD_RUN_ALL\n", _p_ctx->i_thread_sn);

		// wait thread run flag
		do {
			if (is_file_exist(FILE_FLAG_THREAD_RUN_ALL, i_err_code, str_err)) {
				MYLOG_D(">> thread_proc_read[%d] find FILE_FLAG_THREAD_RUN_ALL, will be run\n", _p_ctx->i_thread_sn);
				break;
			}

			usleep(US_SLEEP_VAL_FO_READER);
		} while (1);

		do {
			if (1 == _p_ctx->i_thread_sn) {
				if (is_file_exist(FILE_FLAG_DEBUG, i_err_code, str_err)) {
					if (1 == _p_ctx->i_thread_sn) {
						MYLOG_D(""); // for debug #1 thread
					}
				}
			}
			
			if (_p_ctx->b_request_quit_thread) {
				MYLOG_D(">> thread_proc_read[%d] find b_request_quit_thread, will be quit\n", _p_ctx->i_thread_sn);
				break;
			}

			// read_and_show_context(_p_ctx);
			calc_tps_and_show(_p_ctx);
			
			usleep(US_SLEEP_VAL_FO_READER);
		} while (1);

	} while (0);

	if (NULL != _p_ctx) {
		MYLOG_D("<< thread_proc_read[%d]\n", _p_ctx->i_thread_sn);
		pthread_exit((void*)(intptr_t)_p_ctx->i_thread_sn);
	} else {
		MYLOG_D("<< thread_proc_read\n");
		pthread_exit(NULL);
	}

	return NULL;
}

// @ref https://computing.llnl.gov/tutorials/pthreads/
// POSIX Threads Programming

int fn_test(int argc, char** argv)
{
	bool b_rc = false;
	int i_err_code = 0;
	long l_cpu_numbers = 0;
	long l_thread_numbers = 0;
	std::string str_err = "";

	TAG_THREAD_CONTEXT* p_thread_ctx = NULL;
	TAG_THREAD_SHARE_DATA share_data;
	pthread_attr_t thread_attr;
	int i = 0;
	int i_thread_sn_env_check = 0; // 環境檢測執行緒的號碼

	PFN_thread_proc_env_check pfn_thread_proc_now = NULL;
	
    MYLOG_D(">> fn_test()\n");
	l_cpu_numbers = sysconf(_SC_NPROCESSORS_ONLN);
	MYLOG_D("l_cpu_numbers = %ld\n", l_cpu_numbers);

	l_thread_numbers = l_cpu_numbers * 2;
	MYLOG_D("l_thread_numbers = %ld\n", l_thread_numbers);

	pthread_attr_init(&thread_attr);
	pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);

	// create thread, 
	p_thread_ctx = new TAG_THREAD_CONTEXT[l_thread_numbers];
	for (i = 0; i < l_thread_numbers; i++) {
		p_thread_ctx[i].p_thread_ctx_parent = p_thread_ctx;
		p_thread_ctx[i].l_thread_numbers = l_thread_numbers;
		p_thread_ctx[i].p_share_data = &share_data;
		p_thread_ctx[i].i_thread_sn = i;
		if (i == (l_thread_numbers - 1)) {
			// 最後一個執行緒
			// 最後一個執行緒是檢測執行緒(檢測是否要退出, 如果檢測操作放在主執行緒中, 優先順序低, 沒機會執行到檢測程式碼)
			// 因為要操作其他執行緒控制代碼(e.g. 發現shutdown檔案標誌後), 如果shutdown檔案已經存在,
			// 這種場景下, 如果其他執行緒還沒建立,去操作其他無效的執行緒控制代碼,會崩潰(segment fault)
			pfn_thread_proc_now = thread_proc_env_check;
			i_thread_sn_env_check = i; // 儲存管理執行緒的號碼
		} else {
			switch (i) {
				// case 不能為變數...
				case 0: {
						// 1#執行緒是寫執行緒, 
						pfn_thread_proc_now = thread_proc_write;
					}
					break;
				default: {
						// 其他執行緒是讀執行緒
						pfn_thread_proc_now = thread_proc_read;
					}
					break;
			}
		}
		
		if (EOK == pthread_create(
			&p_thread_ctx[i].h_thread, 
			&thread_attr, 
			pfn_thread_proc_now, 
			p_thread_ctx + i))
		{
			p_thread_ctx[i].b_init_h_thread = true;
			MYLOG_D("ok : pthread[%d] create\n", p_thread_ctx[i].i_thread_sn);
		} else {
			MYLOG_D("error : pthread[%d] create : %s\n", p_thread_ctx[i].i_thread_sn, strerror(errno));
			break;
		}
	}
	
	do {
		if (is_file_exist(FILE_FLAG_SHUTDOWN, i_err_code, str_err)) {
			MYLOG_D("find shutdown file\n");

			pthread_attr_destroy(&thread_attr);

			// 停掉環境檢測執行緒(環境檢測執行緒負責停掉其他執行緒)
			if (pthread_kill(p_thread_ctx[i_thread_sn_env_check].h_thread, 0) == 0) {
				// if thread is still active, first set thread quit falg
				// thread will quit by p_thread_ctx[i_thread_sn_env_check].b_request_quit_thread
				p_thread_ctx[i_thread_sn_env_check].b_request_quit_thread = true;
				MYLOG_D("stop thread_env_check ...\n");
				pthread_join(p_thread_ctx[i_thread_sn_env_check].h_thread, NULL);
			}

			MYLOG_D("ok : stop thread_env_check\n");
			break;
		}

		// if not recv user quit command(/var/log/shutdown_test_time), run continue;
		usleep(US_SLEEP_VAL_FO_READER);
	} while (1);

	SAFE_DELETE_ARY(p_thread_ctx);

    return b_rc;
}


// @file const_define.h

#if not defined(__CONST_DEFINE_H__)
#define __CONST_DEFINE_H__

#include <string.h>
#include <string>
#include <list>
#include <syslog.h>

#define PROG_VER "1.0.0.1"
#define RELEASE_TIME "2018-11-11 14:04"

typedef unsigned long long ull;

#ifndef EOK
#define EOK 0
#endif // #ifndef EOK

#define MAX_MSG_LENGTH (1024 * 4)
	
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) \
    if (NULL != (p)) { \
        delete (p); \
        (p) = NULL; \
    }
#endif // #ifndef SAFE_DELETE

#ifndef SAFE_DELETE_ARY
#define SAFE_DELETE_ARY(p) \
    if (NULL != (p)) { \
        delete[] (p); \
        (p) = NULL; \
    }
#endif // #ifndef SAFE_DELETE

#define TITLE_LINE80 "================================================================================"
#define LINE80 "--------------------------------------------------------------------------------"

#if not defined(MYLOG_D)
#define MYLOG_D(fmt, ...) \
do { \
    syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "MY_LOGD", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
} while (0);
#endif // #if not defined(MYLOG_D)

#define FILE_FLAG_SHUTDOWN "/var/log/test_time__file_flag_to_shutdown"
#define FILE_FLAG_THREAD_RUN_ALL "/var/log/test_time__file_flag_to_thread_run_all"
#define FILE_FLAG_DEBUG "/var/log/test_time__file_flag_to_debug"

#define US_SLEEP_VAL_FO_WRITER 10 // 10微妙
#define US_SLEEP_VAL_FO_READER 1000000 // 1秒

#endif // #if not defined(__CONST_DEFINE_H__)


# ==============================================================================
# @file makefile
# ==============================================================================
# @note 
# howto build project
# 		make BIN_NAME="bin_name_by_you_want" rebuild
# makefile code need tab key not sapce key

MY_MAKE_FILE_PATH_NAME = $(MAKEFILE_LIST)

# macro from Makefile command line
# BIN_NAME

# macro to C project
MAKE_FILE_MACRO__BIN_NAME="make_file_macro__bin_name"

# var define on Makefile
BIN = output_not_give_bin_name
IS_BUILD_TYPE_VALID = 0

ifdef BIN_NAME
	IS_BUILD_TYPE_VALID = 1
	BIN = $(BIN_NAME)
	MAKE_FILE_MACRO__BIN_NAME=$(BIN_NAME)
else
	IS_BUILD_TYPE_VALID = 0
endif

LINE80 = --------------------------------------------------------------------------------

# CC = g++ -std=c++98
CC = g++

# -Werror is "warning as error"
CFLAGS = -Wall -Werror -g

INC = -I.
LIBPATH = -L/usr/lib/ -L/usr/local/lib/

ifeq (1, $(IS_BUILD_TYPE_VALID))
	LIBS = -lstdc++ -pthread
else
	LIBS =
endif

DEPEND_CODE_DIR = ../common/ \

DEPEND_CODE_SRC = $(shell find $(DEPEND_CODE_DIR) -name '*.cpp')
DEPEND_CODE_OBJ = $(DEPEND_CODE_SRC:.cpp=.o)

ROOT_CODE_SRC = $(shell find ./ -name '*.cpp')
ROOT_CODE_OBJ = $(ROOT_CODE_SRC:.cpp=.o)

SUB_CODE_DIR = ./empty_dir
SUB_CODE_SRC = $(shell find $(SUB_CODE_DIR) -name '*.cpp')
SUB_CODE_OBJ = $(SUB_CODE_SRC:.cpp=.o)

.PHONY: help
help:
	clear
	@echo "usage:"
	@echo
	@echo "build project by given bin name"
	@echo "make BIN_NAME=\"bin_name_by_you_want\" rebuild"
	@echo

.PHONY: clean
clean:
	clear

	@echo
	@echo
	@echo
	@echo
	@echo
	@echo
	@echo
	@echo
	@echo
	@echo

	@echo
	@echo
	@echo
	@echo
	@echo
	@echo
	@echo
	@echo
	@echo
	@echo

	@echo
	@echo
	@echo
	@echo
	@echo

	@echo "make clean begin"
	@echo $(LINE80)

	@echo "@file $(MY_MAKE_FILE_PATH_NAME)"
	@echo "IS_BUILD_TYPE_VALID = $(IS_BUILD_TYPE_VALID)"
	@echo "BIN = $(BIN)"

	@echo $(LINE80)

	rm -f $(ROOT_CODE_OBJ) $(DEPEND_CODE_OBJ) $(SUB_CODE_OBJ)

ifeq (1, $(IS_BUILD_TYPE_VALID))
	rm -f ./$(BIN)
endif

	@echo "make clean over"

.PHONY: all
all:$(BIN)
	@echo $(LINE80)
	@echo make all
	chmod 777 ./$(BIN)
	find . -name "$(BIN)"

$(BIN) : $(ROOT_CODE_OBJ) $(DEPEND_CODE_OBJ) $(SUB_CODE_OBJ)
	$(CC) $(CFLAGS) -o [email protected] $^ $(SHLIBS) $(INC) $(LIBPATH) $(LIBS)

.cpp.o:
	$(CC) -c $(CFLAGS) -DMAKE_FILE_MACRO__BIN_NAME="\"$(MAKE_FILE_MACRO__BIN_NAME)\"" $^ -o [email protected] $(INC) $(LIBPATH) $(LIBS)

.PHONY: rebuild
rebuild:
	make -f $(MY_MAKE_FILE_PATH_NAME) clean

ifeq (1, $(IS_BUILD_TYPE_VALID))
	@echo $(LINE80)
	make -f $(MY_MAKE_FILE_PATH_NAME) all
	chmod 775 ./$(BIN)
	ldd ./$(BIN)
else
	@echo $(LINE80)
	@echo "error : Makefile command line input error, please see help"	
	@echo "please run => make help"	
	@echo $(LINE80)
endif


#!/bin/bash
# ==============================================================================
# @file build_all_project.sh
# ==============================================================================

make BIN_NAME="test_time" rebuild