簡單多執行緒程式設計中的切換問題(os-hw4)
阿新 • • 發佈:2020-10-09
寫一個 2 執行緒的程式:
首先生成一個從 1 到 1000 萬的整數陣列,然後用兩個執行緒分別計算陣列奇數部分和偶數部分的和,並打印出總的和。(採用 pthread API )
#include <stdio.h> #include <pthread.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/syscall.h> #include <unistd.h> #include <stdlib.h> #define N 10000000 #define STEP 2 long int integer[N]; void *sumf(void *t) { extern long int integer[N]; int ini = *(int *)t; if (integer[ini] % STEP) printf("odd sum"); else printf("even sum"); long int s = 0; for (int i = ini; i < N; i += STEP) { s = s + integer[i]; } printf(": %ld\t", s); } int main() { // array of integers extern long int integer[N]; for (int i = 0; i < N; i++) integer[i] = i + 1; // sample output long int s_spl = 0; for (int i = 0; i < N; i += STEP) s_spl += integer[i]; printf("sample:\todd sum: %ld", s_spl); s_spl = 0; for (int i = 1; i < N; i += 2) s_spl += integer[i]; printf("\teven sum: %ld\n", s_spl); // 2 threads printf("2 threads:\n\t"); pthread_t th1, th2; // time1 struct timeval t0, t1; time_t sec0; suseconds_t msec0; gettimeofday(&t0, NULL); int para0 = 0, para1 = 1; pthread_create(&th1, NULL, sumf, (void *)¶0); pthread_create(&th1, NULL, sumf, (void *)¶1); pthread_join(th1, NULL); pthread_join(th2, NULL); // time2 gettimeofday(&t1, NULL); sec0 = t1.tv_sec - t0.tv_sec; msec0 = t1.tv_usec - t0.tv_usec; printf("\n\t(glibc) time used:%ld.%ldms\n", sec0 * 1000, msec0); return 0; }
編譯執行的結果:
$ gcc hw4.c -lm -O3 -g -o hw4 -lpthread # 在最後連結pthread的動態庫
$ ./hw4
sample: odd sum: 25000000000000 even sum: 25000005000000
2 threads:
odd sumeven sum: 25000000000000 : 25000005000000
(glibc) time used:0.4862ms
可以發現最後輸出格式略奇怪,檢查 sumf 函式,發現它的結構大致為:if-calc()-prtf(res),由於 pthread_create 產生的執行緒可能在執行中隨機切換(即執行緒內有序,執行緒間隨機),因此有可能執行完 th1 的 if 段後切換到 th2 執行,從而使輸入格式不符合預期(在程式上並沒有毛病)。
為了改善這種情況,注意到 printf 提供的是封裝的核心態函式的使用者態介面,因此考慮把 if 的 print 和 res 的print合併使用 printf,新的 sumf 如下:
void *sumf(void *t) { extern long int integer[N]; int ini = *(int *)t; // 把求和放在前面 long int s = 0; for (int i = ini; i < N; i += STEP) { s = s + integer[i]; } // 合併輸出想要的結果 if (integer[ini] % STEP) printf("odd sum: %ld\t", s); else printf("even sum: %ld\t", s); }
得到的結果即修正為:
$ gcc hw4.c -lm -O3 -g -o hw4 -lpthread
$ ./hw4
sample: odd sum: 25000000000000 even sum: 25000005000000
2 threads:
odd sum: 25000000000000 even sum: 25000005000000
(glibc) time used:0.4958ms
該修改的效用得到驗證。