線程創建、退出


創建線程實際上就是確定調用該線程函數的入口點,線程的創建采用函數 pthread_create。在線程創建以后,就開始運行相關的線程函數,在該函數運行完之后,線程就退出,這也是線程退出的一種方式。另一種線程退出的方式是使用函數 pthread_exit() 函數,這是線程主動退出行為。這里要注意的是,在使用線程函數時,不能隨意使用exit退出函數進行出錯處理,由於exit的作用是使調用進程終止,往往一個進程包括了多個線程,所以在線程中通常使用 pthread_exit 函數來代替進程中的退出函數exit

由於一個進程中的多個線程是共享數據段的,因此通常在線程退出之后,退出線程所占用的資源並不會隨着線程的終止而得到釋放。正如進程之間可以通過wait()函數系統調用來同步終止並釋放資源一樣,線程之間也有類似的機制,那就是 pthread_join 函數。pthread_join 函數可以用於將當前線程掛起,等待線程的結束。這個函數是一個線程阻塞函數,調用它的函數將一直等待直到被等待的線程結束為止,當函數返回時,被等待線程的資源被回收。

函數原型:

#include <pthread.h>

int pthread_create(pthread_t* thread, pthread_attr_t * attr, void *(*start_routine)(void *), void * arg);

void pthread_exit(void *retval);

通常的形式為:

pthread_t pthid;

pthread_create(&pthid,NULL,pthfunc,NULL);    

pthread_create(&pthid,NULL,pthfunc,(void*)3);

pthread_exit(NULL);     

pthread_exit((void*)3);                                //3作為返回值被pthread_join函數捕獲。

函數pthread_create用來創建線程。返回值:成功,則返回0;失敗,則返回對應錯誤碼各參數描述如下:

·參數thread是傳出參數,保存新線程的標識

·參數attr是一個結構體指針,結構中的元素分別指定新線程的運行屬性,attr可以用pthread_attr_init等函數設置各成員的值,但通常傳入為NULL 即可;

·參數start_routine是一個函數指針指向新線程的入口點函數,線程入口點函數帶有一個void *的參數由pthread_create的第4個參數傳入

·參數arg用於傳遞給第3個參數指向的入口點函數的參數,可以為NULL,表示不傳遞

函數pthread_exit表示線程的退出。其參數可以被其它線程用pthread_join函數捕獲。

1、在線程庫里不能使用perror函數查看錯誤
2、能夠perror的函數,函數失敗以后,修改了全局變量 errno,perror讀取error,顯示錯誤
主線程退出,文件描述符關閉,進程地址空間清理

ps -elLf  查看線程
pthread_creat.c pthread_creat_val.c
#include<stdio.h>
#include<pthread.h>

void* threadfunc(void*p)
{
        printf("I am a child thread\n");
        while(1);
}
int main()
{
        pthread_t thdid;
        pthread_create(&thdid,NULL,threadfunc,NULL);
        while(1);
        return 0;
}
#include<stdio.h>
#include<pthread.h>

void* threadfunc(void*p)
{
        int i;
        i=(int)p;
        printf("I am a child thread %d\n",i);
        while(1);
}
int main()
{
        pthread_t thdid;
        pthread_create(&thdid,NULL,threadfunc,(void*)1);
        while(1);
        return 0;
}


    //進程相同,所以父進程也相同(4961),但是線程號不相同 5100、5101

然后  cd /proc , proc下面每一個文件夾都是一個進程: 

//進入我們運行的進程的文件夾,5100,里面都是進程資源,這就是為什么復制進程這么慢,它里面的資源都要復制一份,線程則不同,它共享這些東西,只有task里面的東西是自己獨有的
     //這里面就是我們的線程


ps -elLf  查看線程   編譯加上 -lpthread

(uname -m)  查看ubuntu版本是多少位的

(cd  /proc)里面存儲的都是進程,然后cd到剛才程序的進程號文件夾(cd 進程),在進入task查看線程

pthread_creat_arg1.c
#include<stdio.h>
#include<pthread.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
void *thread_func(void *p)
{
        strcpy((char*)p,"hello,world!");
        printf("I am child thread  , p's address = %p\n",p);
        printf("child thread p=%s\n",(char*)p);
        return 0;
}
int main(void)
{
        pthread_t pt_id;
        void *p = malloc(20*sizeof(char));
        pthread_create(&pt_id,NULL,thread_func,p);
        printf("p's address = %p\n",p);   //%p 打印指針地址
        sleep(2);
        printf("main thread , p=%s\n",(char*)p);
        return 0;
}
// %p


// %x



pthread_exit.c
#include<stdio.h>
#include<pthread.h>
#include<string.h>
#include<unistd.h>

void* threadfunc(void*p)
{
        strcpy((char*)p,"hello");
        printf("I am a child thread %s\n",(char*)p);
        printf("child p is %x\n",p);
        pthread_exit((void*)0);     //退出值是0,就可以直接寫NULL,表示沒有返回值
}
int main()
{
        pthread_t thdid;
        void* p=malloc(20);
        printf("p is %x\n",p);
        printf("I am a father thread %s\n",(char*)p);   //線程共享資源,這里字符串打印的是空的
        int ret = pthread_create(&thdid,NULL,threadfunc,p);
        if(ret!=0)
        {
                printf("error pthread_create\n");
                return -1;
        }
        sleep(1);
        printf("I am a father thread after sleep %s\n",(char*)p);   
        return 0;
}

退出,返回一個整數,要在主線程用函數拿到這個整數



2. 線程的等待退出

等待線程退出:

            線程從入口點函數自然返回,或者主動調用pthread_exit()函數,都可以讓線程正常終止。

            線程從入口點函數自然返回時,函數返回值可以被其它線程用pthread_join函數獲取。


pthread_join原型為:

       #include <pthread.h>

   int pthread_join(pthread_t th, void **thread_return);


1.該函數是一個阻塞函數一直等到參數 th 指定的線程返回與多進程中的waitwaitpid類似。

thread_return是一個傳出參數,接收線程函數的返回值。如果線程通過調用pthread_exit()終止,則 pthread_exit() 中的參數相當於自然返回值,照樣可以被其它線程用pthread_join()獲取到


2.thid傳遞0值時,join返回ESRCH錯誤。




//創建線程,通過pthread_join拿到我們的線程的返回值
pthread_exit(int).c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void* thread(void* p)
        strcpy((char*)p,"hello");
        printf("I am child thread\n");
        printf("child p is %p\n",p);
        pthread_exit((void*)5);              //通過pthread_exit實現線程退出,沒有返回值,就寫pthread_exit(NULL);
}

int main()
{
        pthread_t th_id;
        void* p=malloc(20);
        printf("p is %p\n",p);
        int ret=pthread_create(&th_id,NULL,thread,p);           //創建線程,將數值放入指針內
        if(ret!=0)
        {
                printf("pthread_create failed ret=%d\n",ret);
                return -1;
        }
        int i;        
        //void *i;      //申請了一塊內存,void *,到時候把這個傳給下面函數,函數操作會給你這塊內存自己定好偏移,附上值,也就是這塊地址開始的內存里就存的是上面退出的5;所以最后能直接(int)i;
        ret=pthread_join(th_id,(void**)&i);     //函數規定第二個形參要是一個void**,i來接數據,所以必須取地址
//要用 i 來接返回值,也就是要改變 i 所以必須取地址,但是取完一次地址就不能再取地址,最后轉成(void**);
        if(ret!=0)
        {
                printf("pthread_join failed ret=%d\n",ret);
                return -1;
        }
        printf("main thread %s\n",(char*)p);
        printf("main thread i=%d\n",i);
        //printf("main thread i=%d\n",(int)((int*)i));
        //printf("main thread i=%d\n",(int)i);
        return 0;
}


void* 表示拿一個地址,所有地址都可以默認轉void*,但是如果拿到地址要進行操作,就必須轉成對應類型的指針,因為它要知道偏移量

//創建線程,子線程結束后,malloc內存依然能夠使用
pthread_malloc.c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void* thread(void* p)
        p=malloc(20);
        strcpy((char*)p,"hello");
        printf("I am child thread\n");
        printf("child p is %p\n",p);
        return p;
}

int main()
{
        pthread_t th_id;
        int ret=pthread_create(&th_id,NULL,thread,NULL); //創建線程,將數值放入指針內
        if(ret!=0)
        {
                printf("pthread_create failed ret=%d\n",ret);
                return -1;
        }
        char* p;                  //void* p;
        ret=pthread_join(th_id,(void**)&p);          //要改變p所存的地址,所以&p
        if(ret!=0)
        {
                printf("pthread_join failed ret=%d\n",ret);
                return -1;
        }
        printf("p = %p\n",p);
        printf("p = %s\n",p);        //(char*)p
        return 0;
}



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM