線程和多線程
頭文件:<pthread.h>
函數(shù)原型:int pthread_create(pthread_t restrict tidp,const pthread_attr_t restrict_attr,void(start_rtn)(void*),void *restrict arg);
參數(shù)及返回值:
第一個參數(shù)為指向線程文件句柄的指針。
第二個參數(shù)用來設(shè)置線程屬性。
第三個參數(shù)是線程運行函數(shù)的地址。
最后一個參數(shù)是運行函數(shù)的參數(shù)。
若成功則返回0,否則返回出錯編號
鏈接動態(tài)庫:libpthread.so
實際使用中第二個參數(shù)和最后一個參數(shù)可設(shè)置為NULL或數(shù)字0
信號量
頭文件:<sys/signal.h> #Linux系統(tǒng)下的多線程遵循POSIX線程接口,這是屬于系統(tǒng)調(diào)用的相關(guān)方法
使用也比較簡單,就是設(shè)置好相應(yīng)的參數(shù)就可以了,主要是了解對于參數(shù)的含義,沒有必要全部了解,知道常用的就可以了,比如本次Demo中會用到的幾個我都會仔細說明。
SIGINT:
程序終止(interrupt)信號, 在用戶鍵入INTR字符(通常是Ctrl-C)時發(fā)出,用于通知前臺進程組終止進程。
SIGQUIT:
和SIGINT類似, 但由QUIT字符(通常是Ctrl-)來控制. 進程在因收到SIGQUIT退出時會產(chǎn)生core文件, 在這個意義上類似于一個程序錯誤信號。
SIGTERM:
程序結(jié)束(terminate)信號, 與SIGKILL不同的是該信號可以被阻塞和處理。通常用來要求程序自己正常退出,shell命令kill缺省產(chǎn)生這個信號。如果進程終止不了,我們才會嘗試SIGKILL。
SIGSTOP
停止(stopped)進程的執(zhí)行. 注意它和terminate以及interrupt的區(qū)別:該進程還未結(jié)束, 只是暫停執(zhí)行. 本信號不能被阻塞, 處理或忽略
SIG_BLOCK:
按照參數(shù) set 提供的屏蔽字,屏蔽信號。并將原信號屏蔽保存到oldset中。
SIG_UNBLOCK:
按照參數(shù) set 提供的屏蔽字進行信號的解除屏蔽。針對Set中的信號進行解屏。
SIG_SETMASK:
按照參數(shù) set 提供的信號設(shè)置重新設(shè)置系統(tǒng)信號設(shè)置。
這里咋們先實現(xiàn)一個小的信號Demo
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void* func(void* temp)
{
printf("~~^o^~~\n");
}
int main()
{
signal(SIGINT,func);
while(1)
{
printf("sleeping.......\n");
sleep(1);
}
return 0;
}
這里運行程序按下ctr+c本來可以中斷程序,但是信號的處理函數(shù)被我們換成自定義的了,就會執(zhí)行func函數(shù)下的操作,這時候可以用ctr+\強制結(jié)束程序,相當(dāng)于發(fā)送信號SIGQUIT。
如何設(shè)計實用的多線程場景
在實際項目開發(fā)中使用多線程是很小心的,要注意各種問題,主要還是和需求相關(guān),比如線程的mask信息是繼承自進程,多個線程的資源管理問題,信號處理問題,文件鎖問題。
#include<signal.h>
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
void * thread_sig_wait(void *tmp)
{
int ret,signo;
pthread_t ptid;
//指定被主進程mask的信號,監(jiān)聽并處理
sigset_t sig;
sigemptyset(&sig)
sigaddset(&sig,SIGINT);
sigaddset(&sig,SIGQUIT);
sigaddset(&sig,SIGTERM);
pthread_t pid = pthread_self();
pthread_detach(ptid);
ret = sigwait(&sig,&signo);
printf("ret = %d signo = %d \n",ret,signo);
}
void * func(void *temp)
{
pthread_t pid = pthread_self();
while(1)
{
printf("(^_^)! pid = %lld\n",(long long)pid);
sleep(1);
}
}
int main()
{
pthread_t uid;
sigset_t sig,osig;
//設(shè)置線程mask信號集
//在這里設(shè)置進程需要mask的三個信號,這樣程序就不會被輕易的干掉
//而洗后開啟的線程同樣繼承了主進程的mask,所以線程也捕捉不到這三個信號
//這樣我們再用一個管理線程去添加這三個信號量,捕捉以后可以作其他動作,同時detach,將線程的生命周期和資源與主進程分離
sigemptyset(&sig);
sigemptyset(&osig);
sigaddset(&sig,SIGINT);
sigaddset(&sig,SIGQUIT);
sigaddset(&sig,SIGTERM);
pthread_sigmask(SIG_BLOCK,&sig,&osig);
//開啟等待線程
pthread_create(&uid,0,thread_sig_wait,0);
//開啟多個工作線程
for(int i=0;i<5;i++)
{
pthread_t pid;
pthread_create(&pid,0,func,0);
}
while(1)
{
}
printf("主函數(shù)退出!\n");
return 0;
}
說明:
pthread_detach()
1)pthread_detach()即主線程與子線程分離,子線程結(jié)束后,資源自動回收。
2)函數(shù)說明
函數(shù)原型:int pthread_detach(pthread_t tid);
功能:pthread_join()函數(shù)的替代函數(shù),可回收創(chuàng)建時detachstate屬性設(shè)置為PTHREAD_CREATE_JOINABLE的線程的存儲空間。該函數(shù)不會阻塞父線程。pthread_join()函數(shù)用于只是應(yīng)用程序在線程tid終止時回收其存儲空間。如果tid尚未終止,pthread_detach()不會終止該線程。當(dāng)然pthread_detach(pthread_self())也是可以得
頭文件:#include <pthread.h> pthread非linux系統(tǒng)的默認庫, 需手動鏈接-線程庫 -lpthread
參數(shù):tid:線程標(biāo)識符
返回值:pthread_detach() 在調(diào)用成功完成之后返回零。其他任何返回值都表示出現(xiàn)了錯誤。如果檢測到以下任一情況,pthread_detach()將失敗并返回相應(yīng)的值。
EINVAL:tid是分離線程
ESRCH:tid不是當(dāng)前進程中有效的為分離線