pthread多線程(C語言) + Socket
pthread是使用使用C語言編寫的多線程的API, 簡稱Pthreads ,是線程的POSIX標準,可以在Unix / Linux / Windows 等系統跨平臺使用。在類Unix操作系統(Unix、Linux、Mac OS X等)中,都使用Pthreads作為操作系統的線程。
GitHub項目FanSocket(純C語言socket+線程隊列)+其他demo客戶端
1.線程創建
//子線程1
void test1(int *a){
printf("線程test1");
//修改自己的子線程系統釋放,注釋打開后,線程不能用pthread_join方法
//pthread_detach(pthread_self());
}
//子線程2
void test2(int *a){
printf("線程test2");
}
/*
int pthread_create(pthread_t * thread, //新線程標識符
pthread_attr_t * attr, //新線程的運行屬性
void * (*start_routine)(void *), //線程將會執行的函數
void * arg);//執行函數的傳入參數,可以為結構體
*/
//創建線程方法一 (手動釋放線程)
int a=10;
pthread_t pid;
pthread_create(&pid, NULL, (void *)test1, (void *)&a);
//線程退出或返回時,才執行回調,可以釋放線程占用的堆棧資源(有串行的作用)
if(pthread_join(pid, NULL)==0){
//線程執行完成
printf("線程執行完成:%d\n",threadIndex);
if (message!=NULL) {
printf("線程執行完成了\n");
}
}
//創建線程方法二 (自動釋放線程)
//設置線程屬性
pthread_attr_t attr;
pthread_attr_init (&attr);
//線程默認是PTHREAD_CREATE_JOINABLE,需要pthread_join來釋放線程的
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//線程并發
int rc=pthread_create(&pid, &attr, (void *)test2, (void *)a);
pthread_attr_destroy (&attr);
if (rc!=0) {
printf("創建線程失敗\n");
return;
}
2.線程退出和其他
pthread_exit (tes1) //退出當前線程
pthread_main_np () // 獲取主線程
//主線程和子線程
if(pthread_main_np()){
//main thread
}else{
//others thread
}
int pthread_cancel(pthread_t thread);//發送終止信號給thread線程,如果成功則返回0
int pthread_setcancelstate(int state, int *oldstate);//設置本線程對Cancel信號的反應
int pthread_setcanceltype(int type, int *oldtype);//設置本線程取消動作的執行時機
void pthread_testcancel(void);//檢查本線程是否處于Canceld狀態,如果是,則進行取消動作,否則直接返回
3 線程互斥鎖(量)與條件變量
3.1 互斥鎖(量)
//靜態創建
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//動態創建
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
//注銷互斥鎖
int pthread_mutex_destroy(pthread_mutex_t *mutex);
//lock 和unlock要成對出現,不然會出現死鎖
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
//判斷是否可以加鎖,如果可以加鎖并返回0,否則返回非0
int pthread_mutex_trylock(pthread_mutex_t *mutex);
3.2 條件變量
- 條件變量是利用線程間共享的全局變量進行同步的一種機制,
- 一個線程等待”條件變量的條件成立”而掛起;
- 另一個線程使”條件成立”(給出條件成立信號)。
- 為了防止競爭,條件變量的使用總是和一個互斥鎖結合在一起。
//靜態創建
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
//動態創建
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
//注銷條件變量
int pthread_cond_destroy(pthread_cond_t *cond);
//條件等待,和超時等待
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec *abstime);
//開啟條件,啟動所有等待線程
int pthread_cond_broadcast(pthread_cond_t *cond);
//開啟一個等待信號量
int pthread_cond_signal(pthread_cond_t *cond);
4.線程同步:互斥鎖(量)與條件變量(具體封裝實現)
/*全局的隊列互斥條件*/
extern pthread_cond_t fan_cond;
extern pthread_cond_t fan_cond_wait;
/*全局的隊列互斥鎖*/
extern pthread_mutex_t fan_mutex;
//extern pthread_mutex_t fan_mutex_wait;
extern int fan_thread_status;//0=等待 1=執行 -1=清空所有
extern int fan_thread_clean_status;//0=默認 1=清空所有
//開啟線程等待 return=-2一定要處理
extern int fan_thread_start_wait(void);
//正常的超時后繼續打開下一個信號量 return=-2一定要處理
int fan_thread_start_timedwait(int sec);
//啟動線程,啟動信號量
extern int fan_thread_start_signal(void);
//啟動等待信號量
extern int fan_thread_start_signal_wait(void);
//暫停線程
extern int fan_thread_end_signal(void);
//初始化互斥鎖
extern int fan_thread_queue_init(void);
//釋放互斥鎖信號量
extern int fan_thread_free(void);
//讓隊列里面全部執行完畢,而不是關閉線程;
extern int fan_thread_clean_queue(void);
//每次關閉清空后,等待1-2秒,要恢復狀態,不然線程添加
extern int fan_thread_init_queue(void);
//設置線程的優先級,必須在子線程
extern int fan_thread_setpriority(int priority);
線程隊列互斥,并且按入隊順序,一個一個按照外部條件,觸發信號量,主要是等待隊列,
/*全局的隊列互斥條件*/
pthread_cond_t fan_cond=PTHREAD_COND_INITIALIZER;
pthread_cond_t fan_cond_wait=PTHREAD_COND_INITIALIZER;
/*全局的隊列互斥鎖*/
pthread_mutex_t fan_mutex = PTHREAD_MUTEX_INITIALIZER;
//pthread_mutex_t fan_mutex_wait = PTHREAD_MUTEX_INITIALIZER;
int fan_thread_status=1;//0=等待 1=執行
int fan_thread_clean_status;//0=默認 1=清空所有
//開啟線程等待
int fan_thread_start_wait(void){
pthread_mutex_lock(&fan_mutex);
fan_thread_clean_status=0;
while (fan_thread_status==0) {
pthread_cond_wait(&fan_cond, &fan_mutex);
if (fan_thread_clean_status==1) {
break;
}
}
if (fan_thread_clean_status==1) {
pthread_mutex_unlock(&fan_mutex);
return -2;
}
if (fan_thread_status==1) {
fan_thread_status=0;
pthread_mutex_unlock(&fan_mutex);
}else{
pthread_mutex_unlock(&fan_mutex);
}
return 0;
}
//正常的超時后繼續打開下一個信號量
int fan_thread_start_timedwait(int sec){
int rt=0;
pthread_mutex_lock(&fan_mutex);
struct timeval now;
struct timespec outtime;
gettimeofday(&now, NULL);
outtime.tv_sec = now.tv_sec + sec;
outtime.tv_nsec = now.tv_usec * 1000;
int result = pthread_cond_timedwait(&fan_cond_wait, &fan_mutex, &outtime);
if (result!=0) {
//線程等待超時
rt=-1;
}
if (fan_thread_clean_status==1) {
rt = -2;
}
pthread_mutex_unlock(&fan_mutex);
return rt;
}
//啟動線程,啟動信號量
int fan_thread_start_signal(void){
int rs=pthread_mutex_trylock(&fan_mutex);
if(rs!=0){
pthread_mutex_unlock(&fan_mutex);
}
fan_thread_status=1;
pthread_cond_signal(&fan_cond);
// pthread_cond_broadcast(&fan_cond);//全部線程
pthread_mutex_unlock(&fan_mutex);
return 0;
}
//開啟等待時間的互斥信號量
int fan_thread_start_signal_wait(void){
int rs=pthread_mutex_trylock(&fan_mutex);
if(rs!=0){
pthread_mutex_unlock(&fan_mutex);
}
// fan_thread_status=1;
pthread_cond_signal(&fan_cond_wait);
// pthread_cond_broadcast(&fan_cond);//全部線程
pthread_mutex_unlock(&fan_mutex);
return 0;
}
//暫停下一個線程
int fan_thread_end_signal(void){
pthread_mutex_lock(&fan_mutex);
fan_thread_status=0;
pthread_cond_signal(&fan_cond);
pthread_mutex_unlock(&fan_mutex);
return 0;
}
//初始化互斥鎖(動態創建)
int fan_thread_queue_init(void){
pthread_mutex_init(&fan_mutex, NULL);
pthread_cond_init(&fan_cond, NULL);
return 0;
}
//釋放互斥鎖和信號量
int fan_thread_free(void)
{
pthread_mutex_destroy(&fan_mutex);
pthread_cond_destroy(&fan_cond);
return 0;
}
//清空所有的隊列
int fan_thread_clean_queue(void){
pthread_mutex_lock(&fan_mutex);
fan_thread_clean_status=1;
pthread_cond_broadcast(&fan_cond);
pthread_cond_broadcast(&fan_cond_wait);
pthread_mutex_unlock(&fan_mutex);
return 0;
}
//恢復隊列
int fan_thread_init_queue(void){
pthread_mutex_lock(&fan_mutex);
fan_thread_clean_status=0;
fan_thread_status=1;
pthread_cond_signal(&fan_cond);
pthread_mutex_unlock(&fan_mutex);
return 0;
}
//設置線程的優先級,必須在子線程
int fan_thread_setpriority(int priority){
struct sched_param sched;
bzero((void*)&sched, sizeof(sched));
// const int priority1 = (sched_get_priority_max(SCHED_RR) + sched_get_priority_min(SCHED_RR)) / 2;
sched.sched_priority=priority;
//SCHED_OTHER(正常,非實時)SCHED_FIFO(實時,先進先出)SCHED_RR(實時、輪轉法)
pthread_setschedparam(pthread_self(), SCHED_RR, &sched);
return 0;
}
5 其他線程方法
//return=0:線程存活。ESRCH:線程不存在。EINVAL:信號不合法。
int kill_ret=pthread_kill(pid, 0);//測試線程是否存在
printf("線程狀態:%d\n",kill_ret);
if(kill_ret==0){
//關閉線程
pthread_cancel(pid);
}
pthread_equal(pid, pid1);//比較兩個線程ID是否相同
//函數執行一次
pthread_once_t once = PTHREAD_ONCE_INIT;
pthread_once(&once, test1);