
學習資料https://pan.baidu.com/s/1NZpC4NyH0OHGOPPbO9J10g?pwdh9m2 提取碼: h9m2一. 多線程概念進程是資源分配單位線程是 CPU 調(diào)度單位又叫輕量級進程。同一進程的線程共享地址空間、文件描述符、信號處理等切換代價遠小于進程。Linux 線程是用戶級線程遵循 POSIX 接口pthreadpthread.h編譯加-pthread。為什么用多線程開銷小響應(yīng)快 / 共享數(shù)據(jù)通信方便 / 耗時操作放新線程不影響主線程響應(yīng) / 多 CPU 并行。? 共享內(nèi)存帶來便利也帶來風險訪問共享資源必須做同步與互斥。二. 線程編程2.1 創(chuàng)建pthread_createintpthread_create(pthread_t*tid,constpthread_attr_t*attr,void*(*start_rtn)(void*),void*arg);// 成功 0失敗返回錯誤碼別用 errnoarg傳參傳結(jié)構(gòu)體指針即可線程內(nèi)強轉(zhuǎn)回來。進程的所有信息代碼、全局/堆內(nèi)存、棧、fd對所有線程共享。typedefstructstudent{intage;charname[20];}STU;void*create(void*arg){STU*temp(STU*)arg;printf(STU age is %d, name is %s\n,temp-age,temp-name);}STU*stumalloc(sizeof(STU));stu-age20;strcpy(stu-name,abcdefg);pthread_create(tidp,NULL,create,(void*)stu);pthread_join(tidp,NULL);2.2 終止pthread_exitvoidpthread_exit(void*ret_val);// ret_val 交給 pthread_join正常終止pthread_exit或線程函數(shù)return。? 線程里調(diào)exit()會結(jié)束整個進程pthread_exitexit影響只結(jié)束當前線程整個進程結(jié)束清理函數(shù)先進后出只對pthread_exit有效voidpthread_cleanup_push(void(*rtn)(void*),void*arg);voidpthread_cleanup_pop(intexecute);// 0 不執(zhí)行非 0 執(zhí)行pthread_cleanup_push(clean_1,thread first handler);pthread_cleanup_push(clean_1,thread second hadler);if(i1)pthread_exit(NULL);// 執(zhí)行清理順序是 second → first后進先出elseexit(0);// 對 exit 無效pthread_cleanup_pop(0);pthread_cleanup_pop(0);兩個調(diào)用必須配套線程正常return或exit時清理函數(shù)不會執(zhí)行。2.3 等待pthread_joinintpthread_join(pthread_tthread,void**thread_return);// 掛起自己等指定線程結(jié)束只能等待同一進程的線程? 一個線程不能被多個線程 join。void*t2_exe(void*arg){pthread_join((pthread_t)arg,NULL);// 先把線程1 join 掉printf(The second thread:\n);// 線程1結(jié)束后才打印 6~10}pthread_create(pid1,NULL,t1_exe,NULL);pthread_create(pid2,NULL,t2_exe,(void*)pid1);2.4 獲取自身線程號pthread_tpthread_self(void);// 同一進程內(nèi) pid 相同線程 ID 不同三. 同步與互斥三種機制互斥量、信號量、條件變量。3.1 互斥量 mutex相當于一把鎖保證①原子性臨界區(qū)要么全做要么不做②唯一性解鎖前別人鎖不上③非繁忙等待搶不到鎖就掛起不占 CPU。操作函數(shù)初始化pthread_mutex_init(mutex, NULL)或靜態(tài)PTHREAD_MUTEX_INITIALIZER加鎖pthread_mutex_lock(mutex)搶不到就阻塞嘗試加鎖pthread_mutex_trylock(mutex)占用時返回EBUSY不阻塞解鎖pthread_mutex_unlock(mutex)一般由加鎖者解鎖銷毀pthread_mutex_destroy(mutex)鎖的 4 種屬性PTHREAD_MUTEX_TIMED_NP默認普通鎖排隊公平RECURSIVE_NP嵌套鎖可重復加ERRORCHECK_NP檢錯鎖重復加鎖返回EDEADLKADAPTIVE_NP適應(yīng)鎖。示例兩個線程按順序遍歷數(shù)組charstr[]abcdefghijklmnopqrstuvwxyz123456789;pthread_mutex_tmutex;intindex20;void*t1_exe(void*arg){while(index2strlen(str)-1){pthread_mutex_lock(mutex);// 不加鎖會出現(xiàn)元素重復打印printf(The %dth element is %c\n,index2,str[index2]);sleep(1);index2;pthread_mutex_unlock(mutex);}}// main: pthread_mutex_init(mutex, NULL); 創(chuàng)建兩個線程都跑 t1_exe3.2 信號量sem_t頭文件semaphore.h互斥用 1 個同步用多個。本質(zhì)是 P/V 原語 非負計數(shù)器。函數(shù)作用int sem_init(sem_t *sem, int pshared, unsigned int value);pshared0線程間共享放全局/堆非 0 進程間共享放共享內(nèi)存int sem_wait(sem_t *sem);P值為 0 阻塞否則減 1int sem_trywait(sem_t *sem);P 非阻塞版int sem_post(sem_t *sem);V加 1 并喚醒一個等待者原子int sem_destroy(sem_t *sem);銷毀sem_getvalue取當前值互斥一個信號量初值 1順序隨機但不同時訪問sem_init(sem,0,1);// 線程1 // 線程2sem_wait(sem);sem_wait(sem);global;global*2;sem_post(sem);sem_post(sem);同步兩個信號量輪流執(zhí)行sem_init(sem1,0,1);sem_init(sem2,0,0);// 線程1: sem_wait(sem1); global; sem_post(sem2);// 線程2: sem_wait(sem2); global*2; sem_post(sem1);// 結(jié)果固定1→2→4→5→10…3.3 條件變量與互斥鎖不同它用來等待而不是上鎖通常與互斥鎖配合。一個線程等條件成立而掛起另一個線程使條件成立并通知。好處避免線程反復加鎖/解鎖卻不干活的忙等。函數(shù)作用pthread_cond_init(cond, NULL)/PTHREAD_COND_INITIALIZER初始化pthread_cond_wait(cond, mutex)解鎖 mutex → 阻塞等待 → 被喚醒后重新加鎖pthread_cond_timedwait(cond, mutex, abstime)超時返回ETIMEpthread_cond_signal(cond)喚醒一個等待線程pthread_cond_destroy(cond)釋放?pthread_cond_wait返回后必須重新判斷條件解鎖→等待→加鎖這三步不是原子操作等待期間條件可能已被別的線程改變。pthread_mutex_tmutex;pthread_cond_tcond;inti1;void*thread1(void*arg)// i 為 9 的倍數(shù)時通知 thread2{for(i1;iMAX;i){pthread_mutex_lock(mutex);if(i%90)pthread_cond_signal(cond);elseprintf(In thread1:%d\n,i);pthread_mutex_unlock(mutex);sleep(1);}}void*thread2(void*flag)// 不是 9 的倍數(shù)就等{while(iMAX){pthread_mutex_lock(mutex);if(i%9!0)pthread_cond_wait(cond,mutex);if(i%90)printf(In thread2:%d\n,i);pthread_mutex_unlock(mutex);sleep(1);}}四. 三種機制怎么選機制著眼點互斥量共享資源的互斥訪問臨界區(qū)同時只進一個線程信號量互斥1 個 同步多個條件變量等待某個條件成立配合互斥量避免忙等互斥/同步會降低一點效率但能保證共享資源一致按需選擇即可。