1. 程式人生 > 其它 >linux--(1)程序的建立與終止

linux--(1)程序的建立與終止

# 執行緒基本概念

基本概念

程序是資源管理的最小單位,執行緒是程式執行的最小單位

程序都有自己的資料段、程式碼段和堆疊。佔用資源比較多

所以演化出執行緒,花費更少的資源

執行緒與程序的關係是:執行緒是屬於程序的

同一執行緒所產生的執行緒共享同一使用者記憶體空間

一個程序至少需要一個執行緒作為他的指令執行體

程序管理者管理著資源(比如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;
}

程序的記憶體分配

  • 執行緒各自的變數儲存線上程各自的棧空間中,互相獨立
  • 資料段的全域性變數為共享資源,執行緒都可以訪問更改,但是為執行緒不安全,需要把他變成執行緒安全。
  • 多執行緒程式設計中推薦使用區域性變數。

# 執行緒終止

執行緒終止的分類:

  1. 主動終止
  • 執行緒的執行函式中呼叫return語句
  • 呼叫pthread_exit()
  1. 被動終止
  • 執行緒可以被同一程序的其他執行緒取消,其他執行緒呼叫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

後續清理更新待寫