1. 線程的創建和退出
創建線程實際上就是確定調用該線程函數的入口點,線程的創建采用函數 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,表示不傳遞。
1、在線程庫里不能使用perror函數查看錯誤
2、能夠perror的函數,函數失敗以后,修改了全局變量
errno,perror讀取error,顯示錯誤
主線程退出,文件描述符關閉,進程地址空間清理
|
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;
}
![]() |

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 指定的線程返回;與多進程中的wait或waitpid類似。
thread_return是一個傳出參數,接收線程函數的返回值。如果線程通過調用pthread_exit()終止,則 pthread_exit() 中的參數相當於自然返回值,照樣可以被其它線程用pthread_join()獲取到。
2.thid傳遞0值時,join返回ESRCH錯誤。
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;
}
|
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;
}
|