linux--(1)程序的建立與終止
阿新 • • 發佈:2021-12-01
# 執行緒基本概念
基本概念
程序是資源管理的最小單位,執行緒是程式執行的最小單位
程序都有自己的資料段、程式碼段和堆疊。佔用資源比較多
所以演化出執行緒,花費更少的資源
執行緒與程序的關係是:執行緒是屬於程序的
同一執行緒所產生的執行緒共享同一使用者記憶體空間
一個程序至少需要一個執行緒作為他的指令執行體
程序管理者管理著資源(比如cpu,記憶體,檔案)而將執行緒分配到某個cpu上執行
理解一下比如:車道 主線路分出其他子線路
執行緒分類
執行緒按其排程者可分為使用者級執行緒和核心級執行緒
1.使用者級執行緒:解決上下文切換的問題,由使用者決定排程過程
2.核心級執行緒:由核心排程機制排程
大多是都用並存
實現執行緒的庫
linux ------- pthread
linux中需要連結執行緒庫pthread
執行緒標識
id
pthread_t資料型別
# 建立執行緒
完成案例:龜兔賽跑
#include<pthread.h> #include<stdio.h> #include<stdlib.h> int main() { int err;//定義錯誤儲存 pthread_t rabbit,turtle;//定義執行緒識別符號 //建立rabbit執行緒 if((err=pthread_create(&rabbit,NULL, th_fn,(void*)50))!=0){ perror("pthread_create error"); return 0; }
先講一下這個建立執行緒幾點
pthread_create(&rabbit,NULL,th_fn,(void*)50)
&rabbit是執行緒標識
NULL表示執行緒屬性指標,表示沒有這個
th_fn:執行緒執行函式
(void*)50:50轉為指標,傳遞給執行緒執行函式的引數
-------------------------------------------------------------------
//drand48 返回服從均勻分佈的·[0.0, 1.0) 之間的 double 型隨機數。
原始碼:
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <math.h> //定義執行緒執行函式 void* th_fn(void *arg) //傳入void*數值 { int distance=(long)arg; //強轉為int,我的是64位的long int i; for (i =1; i <=distance; i++) { printf("%lx run %d\n", pthread_self(),i); int time=(int)(drand48()*100000); usleep(time);//微秒 } return (void*)0; //返回指標 數值0 } int main() { int err;//定義錯誤儲存 pthread_t rabbit,turtle;//定義執行緒識別符號 //建立rabbit執行緒 if((err=pthread_create(&rabbit,NULL, th_fn,(void*)50))!=0){ perror("pthread_create error");} //建立turtle執行緒 if((err=pthread_create(&turtle,NULL, th_fn,(void*)50))!=0){ perror("pthread_create error");} sleep(10);//先睡眠主執行緒,先執行子執行緒 printf("control thread id: %lx\n",pthread_self()); //以十六進位制輸出主控執行緒id printf("fininshed!\n"); return 0; }
主執行緒結束後,碰到return 0就執行緒結束了,所以這裡加一個sleep
執行
交叉執行
distance為50到50,停止
不能每次都這麼好算sleep,sleep不好
所以接著換個方法 pthread_join
//主控執行緒呼叫pthread_join,自己阻塞 //直到rabbit和turtle執行緒結束才執行 pthread_join(rabbit,NULL); pthread_join(turtle,NULL);
效果一樣的
接下來案例二:對第四個引數傳遞具體結構體
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <math.h> //定義結構體型別:新結構體 typedef struct { char name[20]; int time; int start; int end; }RaceArg; //定義執行函式 void* th_fn(void *arg){ RaceArg *r=(RaceArg*)arg; //強轉為結構體指標型別 int i=r->start; for (; i <= r->end; i++) { printf("%s(%lx) running %d\n",r->name,pthread_self(), i); usleep(r->time); } return (void*)0; } int main(void) { int err; pthread_t rabbit,turtle; RaceArg r_a = { "rabbit",(int)(drand48()*100000000),20,50}; RaceArg t_a= {"turtle",(int)(drand48()*100000000),10,60}; if ((err=pthread_create(&rabbit,NULL,th_fn,(void*)&r_a))!=0){ perror("pthread_create error"); } if ((err=pthread_create(&turtle,NULL,th_fn,(void*)&t_a))!=0){ perror("pthread_create error"); } //主控執行緒呼叫pthread_join,自己阻塞, //直到rabbit和turtle執行緒結束才執行 pthread_join(rabbit,NULL); pthread_join(turtle,NULL); printf("control thread id: %lx\n",pthread_self()); //以十六進位制輸出主控執行緒id printf("fininshed!\n"); return 0; }
程序的記憶體分配
- 執行緒各自的變數儲存線上程各自的棧空間中,互相獨立
- 資料段的全域性變數為共享資源,執行緒都可以訪問更改,但是為執行緒不安全,需要把他變成執行緒安全。
- 多執行緒程式設計中推薦使用區域性變數。
# 執行緒終止
執行緒終止的分類:
- 主動終止
- 執行緒的執行函式中呼叫return語句
- 呼叫pthread_exit()
- 被動終止
- 執行緒可以被同一程序的其他執行緒取消,其他執行緒呼叫pthread_cancel(pthid)
執行緒終止的函式
#include <pthread.h> int pthread_cancel(pthread_t tid); void pthread_exit(void *retval); int pthread_join(pthread_t th, void **thread_return); //返回值:成功返回0,否則返回錯誤編號
- pthread_cancel:
- 執行緒可以被同一程序的其他執行緒取消,tid為被終止的執行緒識別符號,pthread_cancel()無法回收資源
- pthread_exit:
- retval: pthread_exit呼叫者執行緒的返回值,可由其他函式和pthread_join來檢測獲取。
- 執行緒退出時使用函式pthread_exit,是執行緒的主動行為。
- 由於一個程序中的多個執行緒共享資料段,因此通常線上程退出後,退出執行緒所佔用的資源並不會隨執行緒結束而釋放。所以需要pthread_join函式來等待執行緒結束,類似於wait系統呼叫。
- pthread_join:
- th:被等待執行緒的識別符號。
- thread_return:使用者定義指標,用來儲存被等待執行緒的返回值。
下面舉幾個例子:
案例1:二哥執行緒 id相加
#include <pthread.h> #include <stdlib.h> #include <stdio.h> typedef struct { int d1; int d2; }Arg; void* th_fn(void* arg) { Arg* r=(Arg*)arg; //強轉為結構體指標 return (void*)(r->d1+r->d2); //輸出是一個指標變數 返回指標 } int main(int argc, char **argv) { int err; pthread_t th; Arg r={20,50}; if(0!=(err = pthread_create(&th,NULL,th_fn,(void*)&r))) perror("pthread_create error"); //當返回為結構體指標 int *result; pthread_join(th, (void**)&result); //指標的指標 使用者定義指標,用來儲存被等待執行緒的返回值。 printf("result is %d\n",(int)result); //強轉為int return 0; }
20+50=70,
這是一種方法
//當返回為結構體指標 // int *result; // pthread_join(th, (void**)&result); //指標的指標 使用者定義指標,用來儲存被等待執行緒的返回值。 // printf("result is %d\n ,(int)result); //強轉為int int result; pthread_join(th,(void*)&result); printf("result is %d\n",result);
效果一樣,返回到result到上 結果70指標、int 變為70
然後void*變為指標
修改返回型別,返回結構體指標
#include <pthread.h> #include <stdlib.h> #include <stdio.h> typedef struct { int d1; int d2; }Arg; void* th_fn(void* arg) { Arg* r=(Arg*)arg; //return (void*)(r->d1+r->d2); //輸出是一個指標變數 return (void*)r; //輸出一個結構體變數指標 } int main(int argc, char **argv) { int err; pthread_t th; Arg r={20,50}; if(0!=(err = pthread_create(&th,NULL,th_fn,(void*)&r))) perror("pthread_create error"); /* int *result; pthread_join(th, (void**)&result); //給th_fn返回的指標變數賦值 printf("result is %d\n",(int)result); */ /*或者 int result; pthread_join(th, (void*)&result); printf("result is %d\n",result); */ //當返回為結構體指標 int *result; pthread_join(th, (void**)&result); printf("result is %d\n",((Arg*)result)->d1+((Arg*)result)->d2); return 0; }
改進龜兔賽跑:
/* * pthread_creat2.c * 龜兔賽跑 */ #include <stdio.h> #include <pthread.h> #include <stdlib.h> #include <math.h> #include <unistd.h> typedef struct { char name[10]; int time; int start; //起始點 int end; //結束點 }RaceArg; void* th_fn(void *arg) { RaceArg *r = (RaceArg*)arg; for(int i=r->start; i<=r->end; ++i) { printf("%s(%lx) running %d\n",r->name,pthread_self(), i); usleep(r->time); } //return (void*)0;//pthread_exit((void*)0); return (void*)(r->end - r->start); } int main(int argc, char **argv) { int err; //錯誤編碼 pthread_t rabbit,turtle; //定義執行緒識別符號 RaceArg r_a= {"rabbit", (int)(drand48()*10000000),20,50}; RaceArg t_a= {"turtle", (int)(drand48()*10000000),10,60}; if(0!=(err = pthread_create(&rabbit, NULL, th_fn, (void*)&r_a ))) //傳入結構體指標 { perror("pthread_create error"); } if(0!=(err = pthread_create(&turtle, NULL, th_fn, (void*)&t_a ))) { perror("pthread_create error"); } int result; pthread_join(rabbit, (void*)&result); printf("rabbit race distance is %d\n", result); pthread_join(turtle, (void*)&result); printf("turtle race distance is %d\n", result); printf("race finished\n"); /* pthread_join(rabbit,NULL); pthread_join(turtle,NULL); */ printf("control thread ID: %lx\n",pthread_self()); printf("finished!\n"); return 0; }
輸出:
turtle(b660c460) running 10 rabbit(b6e0d460) running 20 rabbit(b6e0d460) running 21 rabbit(b6e0d460) running 22 rabbit(b6e0d460) running 23 rabbit(b6e0d460) running 24 rabbit(b6e0d460) running 25 rabbit(b6e0d460) running 26 rabbit(b6e0d460) running 27 rabbit(b6e0d460) running 28 rabbit(b6e0d460) running 29 rabbit(b6e0d460) running 30 rabbit(b6e0d460) running 31 rabbit(b6e0d460) running 32 rabbit(b6e0d460) running 33 rabbit(b6e0d460) running 34 rabbit(b6e0d460) running 35 rabbit(b6e0d460) running 36 rabbit(b6e0d460) running 37 rabbit(b6e0d460) running 38 rabbit(b6e0d460) running 39 rabbit(b6e0d460) running 40 rabbit(b6e0d460) running 41 rabbit(b6e0d460) running 42 rabbit(b6e0d460) running 43 rabbit(b6e0d460) running 44 rabbit(b6e0d460) running 45 rabbit(b6e0d460) running 46 rabbit(b6e0d460) running 47 rabbit(b6e0d460) running 48 rabbit(b6e0d460) running 49 rabbit(b6e0d460) running 50 rabbit race distance is 30 turtle(b660c460) running 11 turtle(b660c460) running 12 turtle(b660c460) running 13 turtle(b660c460) running 14 turtle(b660c460) running 15 turtle(b660c460) running 16 turtle(b660c460) running 17 turtle(b660c460) running 18 turtle(b660c460) running 19 turtle(b660c460) running 20 turtle(b660c460) running 21 turtle(b660c460) running 22 turtle(b660c460) running 23 turtle(b660c460) running 24 turtle(b660c460) running 25 turtle(b660c460) running 26 turtle(b660c460) running 27 turtle(b660c460) running 28 turtle(b660c460) running 29 turtle(b660c460) running 30 turtle(b660c460) running 31 turtle(b660c460) running 32 turtle(b660c460) running 33 turtle(b660c460) running 34 turtle(b660c460) running 35 turtle(b660c460) running 36 turtle(b660c460) running 37 turtle(b660c460) running 38 turtle(b660c460) running 39 turtle(b660c460) running 40 turtle(b660c460) running 41 turtle(b660c460) running 42 turtle(b660c460) running 43 turtle(b660c460) running 44 turtle(b660c460) running 45 turtle(b660c460) running 46 turtle(b660c460) running 47 turtle(b660c460) running 48 turtle(b660c460) running 49 turtle(b660c460) running 50 turtle(b660c460) running 51 turtle(b660c460) running 52 turtle(b660c460) running 53 turtle(b660c460) running 54 turtle(b660c460) running 55 turtle(b660c460) running 56 turtle(b660c460) running 57 turtle(b660c460) running 58 turtle(b660c460) running 59 turtle(b660c460) running 60 turtle race distance is 50 race finished control thread ID: b6fe10b0 finished!View Code
後續清理更新待寫