進程是電腦分配資源的基本單位,線程是cpu調度的基本單位 線程基本概念: LWP:light weight process 輕量級的進程。創建線程的底層函數和進程一樣,都是clone,因此線程的本質仍是進程(在linux環境下) 與進程相比,線程有獨立的TCB結構體(類似於進程的PCB),但沒有獨 ...
進程是電腦分配資源的基本單位,線程是cpu調度的基本單位
線程基本概念:
LWP:light weight process 輕量級的進程。創建線程的底層函數和進程一樣,都是clone,因此線程的本質仍是進程(在linux環境下)
與進程相比,線程有獨立的TCB結構體(類似於進程的PCB),但沒有獨立的地址空間(共用),類似於合租與獨居。
查看線程號(LWP,不是TID)可以用下述命令:
ps -Lf xxx(PID)
線程創建相關函數
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
//=================================屬性設置按需要採用,若普通情況可以不用設置===============//
pthread_attr_t attr; // 定義線程的屬性變數
int pthread_attr_init(pthread_attr_t *attr); // 初始化屬性變數
int pthread_attr_setXXX(pthread_attr_t *attr, ...); // 設置屬性變數的值
//此處僅列舉常用的//
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); // 設置/獲得線程的分離屬性
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched); // 設置/獲得是否繼承創建者的調度策略
int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched);
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); // 設置/獲得調度策略
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param); // 設置/獲得線程的靜態優先順序
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
//=================================上述屬性設置按需要採用,若普通情況可以不用設置===============//
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
// 創建線程,此處void *(*start_routine)(void *)函數指針指向的函數,void *arg作為其參數,並且需要採用值傳遞,如果數據類型不同需要強轉
int pthread_detach(pthread_t thread); // 如果沒有設置線程的分離屬性,可以用此函數強制設為分離屬性,防止線程結束後變為僵屍進程,無法釋放資源,而且不能再用 pthread_join等待回收該進程的資源
pthread_t pthread_self(void); // 創建成功後,可以線上程中使用,獲取當前線程的tid
void pthread_exit(void *retval); // 退出線程,並得到返回值retval
int pthread_cancel(pthread_t thread); // 給指定線程發送一個取消的請求
int pthread_setcancelstate(int state, int *oldstate);
// 設置線程的取消狀態:PTHREAD_CANCEL_ENABLE 可取消; PTHREAD_CANCEL_DISABLE 不可取消
int pthread_setcanceltype(int type, int *oldtype);
// 設置線程的取消類型:PTHREAD_CANCEL_DEFERRED 延時響應; PTHREAD_CANCEL_ASYNCHRONOUS 立即響應。
int pthread_join(pthread_t thread, void **retval); // 接合指定已結束或者待結束的線程,並得到返回狀態值;如果指定的線程還在運行,將會阻塞等待。
應用實例
char *retval = "byebye!\n"; // 假設為共用資源
pthread_mutex_t m; // 定義互斥鎖
void handler(void *arg)
{
pthread_mutex_unlock(&m);
}
void *child_thread(void *arg)
{
while (1)
{
pthread_cleanup_push(handler, NULL); // 上鎖前,需要將handler函數壓入線程取消處理的棧中,以防止該子進程在運行的中途被取消,造成死鎖
pthread_mutex_lock(&m);
printf("Child thread obtain the mutex:%s\n", retval);
pthread_mutex_unlock(&m);
pthread_cleanup_pop(0); // 解鎖後,將handler從棧中彈出,不執行
sleep(2);
}
}
int main()
{
pthread_mutex_init(&m, NULL);
pthread_t tidofparent = pthread_self(); // 接收主線程的tid值。
printf("parent's tid:%ld\n", tidofparent);
printf("parent's tid:%ld\n", sizeof(int));
pthread_t tid;
pthread_create(&tid, NULL, child_thread, NULL); // 新建子線程
// pthread_detach(tid); 讓線程“自立門戶”,結束後資源自動回收,此處與pthread_cancel和pthread_join衝突,
sleep(5);
pthread_cancel(tid); // 5秒後,向子線程發送取消的請求
// 待子線程被取消後,鎖被handler自動釋放,可以繼續加互斥鎖,對公共資源進行操作
pthread_mutex_lock(&m);
retval = "I'm main pthread!\n";
printf("Now I botain the mutex:%s\n", retval);
pthread_mutex_unlock(&m);
/*
void *p;
pthread_join(tid, &p); // 如果沒有採用pthread_cancel(tid)取消子進程,這部分將會阻塞等待子線程結束,接受子線程的返回值並列印
printf("子線程的返退出回值:%s\n", (char *)p);
*/
return 0;
}
註意事項
1.主線程退出也可以用pthread_exit(),其他子線程照樣運行不受影響。但如果主線程運行了return/exit等語句,或者子線程用exit,會導致整個進程退出。
2.避免線程編程僵屍進程的三種方法:
- int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) 提前設置分離屬性
- int pthread_detach(pthread_t thread);子線程創建後強制設置分離屬性
- 線上程結束後利用pthread_join()進行接合。
3.malloc 和mmap 申請的記憶體可以被其他子線程釋放,因為申請出來的都是共用堆地址。
4.信號語義複雜,儘量避免和線程機制混用。