一、線程的基本概念
1、基本概念
線程是特殊的程序,在作業系統中,線程不能獨立存在,線程是程序建立出來的,一個程序可以有多個線程,程序退出了,線程也會跟着退出。
2、資源
每個程序都有自己獨立的堆、棧、資料段、代碼段等空間,線程基本沒有獨立的資源,隻有必不可少的資源(棧),同一程序之間的線程共享程序中的所有資源。
二、線程相關的API
1、線程建立函數
thread:存放線程的id
attr:線程的分離屬性—>NULL
start_routine :參數為void *, 傳回值也是void * 類型的函數指針。(線程執行函數)
arg:函數的參數
傳回值:成功傳回0,失敗傳回非0.
代碼段:
void * Pthread_Task(void *arg)// arg = data;
{
int a = (long)arg;
printf("-----%d\n", a);
}
int main()
{
long data = 110;
//建立線程
pthread_t pid;
int ret = pthread_create(&pid, NULL, Pthread_Task, (void *)data);
if(ret != 0)
{
perror("ptread_create");
return -1;
}
else
{
printf("線程建立成功!\n");
}
}
2、線程的退出
retal: 傳回線程結束的狀态(void*變量)
讓線程退出的三種方法:
-
線程的任務函數調用完傳回退出(直接死),讓其他人給這個死的線程回收線程資源.線程調用這個pthread_exit();
立馬死了,讓其他人給這個死的線程回收線程資源.
- 取消線程 pthreada_cancel:隻是一個請求(不能保證線程肯定會去退出)
-
設定線程位分離屬性,他死了不需要别人給他收屍。
3、線程資源回收函數
thread: 子線程的id
retval: 子線程結束狀态
等待回收子線程的資源(棧空間),作用相當于子線程中的waitpid
pthread_join:預設是堵塞的,自己不能調用pthread_join來回收自己。
4、設定線程分離屬性
1)分離屬性:子線程的資源由系統回收,線程的資源回收需使用pthread_join來實作,如果該線程運作沒有結束,會阻塞主線程,當主線程還要建立新線程來做一些事情,此時主線程就會因為調用pthread_join而被堵塞,就沒辦法處理其他事務,是以引入線程的分離屬性,他不需要主線程回收,在退出系統會自動回收。
線程分離函數:
int pthread_detach(pthread_t thread);
thread:線程id
2)線程建立時選擇分離屬性-----對pthread_create的第二個參數進行設定
pthread_attr_t *attr
定義一個pthread_attr_t 類型變量attr,然後對這個變量attr 進行初始化 pthread_attr_init()最後設定分離屬性。
① 初始化線程屬性
int pthread_attr_init(pthread_attr_t *attr);
② 設定分離屬性
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
5、線程的取消
1)線程取消函數:pthread_cancel()
2)設定線程取消響應—>是否響應取消信号
3)設定響應取消信号的類型---->立即響應、延時響應
代碼段:
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
struct Data
{
char pthread_name[10];
};
void *Pthread_Task(void *arg)
{
//設定線程取消狀态---接受取消請求
int pthread_setcancelstate_ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
if (pthread_setcancelstate_ret != 0)
{
perror("pthread_setcancelstate");
exit(-1);
}
while (1)
{
struct Data *p = (struct Data *)arg;
printf("%s\n", p->pthread_name);
sleep(1);
}
pthread_exit(NULL);
}
int main()
{
pthread_t pid;
struct Data d1;
memset(&d1, 0, sizeof(d1));
strcpy(d1.pthread_name, "hello");
//建立線程
int ret = pthread_create(&pid, NULL, Pthread_Task, (void *)&d1);
if (ret != 0)
{
perror("pthread_create");
exit(-1);
}
printf("5s之後發送取消請求\n");
sleep(5);
//取消線程
pthread_cancel(pid);
pause();
return 0;
}
壓棧和彈棧要配套使用,想讓誰響應注冊函數,那麼就是誰裡面寫壓棧和彈棧。
代碼段:
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
//線程注冊函數
void Pthread_At_Fun(void *arg)
{
printf("%s\n", (char *)arg);
}
//線程任務函數
void *Pthread_Task(void *arg)
{
//壓棧
pthread_cleanup_push(Pthread_At_Fun, (void *)"死亡閃現");
printf("三秒之後我将死亡\n");
sleep(3);
pthread_exit(NULL);
//彈棧
pthread_cleanup_pop(0);
}
int main()
{
//建立線程
pthread_t pid;
int pthread_create_ret = pthread_create(&pid, NULL, Pthread_Task, NULL);
if(pthread_create_ret != 0)
{
perror("pthread_create");
exit(-1);
}
while(1)
{
printf("我看見小線程死亡閃現!\n");
sleep(1);
}
return 0;
}