帶你學習多線程編程
阿新 • • 發佈:2018-05-24
線程 多線程 進程 Linux 線程概念
定義
線程就是進程內部的執行流,一個進程至少有一個線程,線程擁有自己的私有資源同時也會和進程共享資源。
線程獨有的資源
- 線程描述符
- 寄存器
- 線程棧
- errno
- 信號掩碼
- 實時調度策略
線程和進程共享的資源
- 全局變量
- 堆
- 代碼段
- 文件描述符表
- 進程ID和組ID
- 每種信號的處理方式
-
當前工作目錄
線程和進程的區別
- 線程是資源調度的最小單位 ,進程時資源分配的最小單位
- 進程是一次程序運行活動,線程是進程中的一個執行路徑
- 進程之間不能共享資源,而線程共享所在進程的地址空間和其它資源。同時線程還有自己的棧和棧指針,程序計數器等寄存器。
- 進程有自己獨立的地址空間,而線程沒有,線程必須依賴於進程而存在。
線程的創建
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
參數:
- thread:返回線程的id
- attr:線程屬性,可以手動設置(下文將詳細描述線程屬性)
- start_routine:線程執行的函數的函數地址
- arg:線程執行函數的參數
返回值:
成功返回0,失敗返回錯誤碼。線程的終止
有三種方式終止一個線程。
- 用return返回。
- 用pthread_exit();
#include <pthread.h> void pthread_exit(void *retval);
參數:
retval:保存線程退出碼,<font color="#dd00dd">這個指針一定要是全局變量或者堆上開辟的。</font><br/> - 用pthread_cancel()
#include <pthread.h> int pthread_cancel(pthread_t thread);
參數:
thread:結束的線程ID(可以結束任意線程)
返回值:
成功返回0,失敗返回錯誤碼。
線程的終止不能用exit(),這是進程的終止方式。
線程的等待與分離
為什麽需要線程等待
- 不等待,線程結束後不會自動釋放資源。
- 會導致過多線程描述符被占用,無法創建新的線程。
線程等待函數
#include <pthread.h> int pthread_join(pthread_t thread, void **retval);
參數:
thread:等待線程的ID
retval:保存退出狀態碼
返回值:
成功返回0,失敗返回錯誤碼。線程分離
當我們不關心線程的退出狀態,只希望線程結束系統會自動清理和釋放資源,這時我們就可以使用線程分離。
#include <pthread.h> int pthread_detach(pthread_t thread);
參數:
thread:分離的線程ID
返回值:
成功返回0,失敗返回錯誤碼。
線程一旦被pthread_detach()分離,就不能再用pthread_join()獲取其狀態了,也不能再返回鏈接狀態。線程屬性
在前面pthread_create()函數時,就涉及到pthread_attr_t *attr線程屬性,我們可以手動設置線程屬性。
int pthread_attr_init(pthread_attr_t *attr);//初始化線程屬性 int pthread_attr_destroy(pthread_attr_t *attr);//銷毀線程屬性對象
Detach state = PTHREAD_CREATE_JOINABLE//分離屬性 int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);//設置分離屬性 int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);//獲得分離屬性 Scope = PTHREAD_SCOPE_SYSTEM//搶奪資源範圍 Inherit scheduler = PTHREAD_INHERIT_SCHED//是否繼承線程調度策略 Scheduling policy = SCHED_OTHER//調度策略 Scheduling priority = 0//調度優先級 Guard size = 4096 bytes//線程棧之間的安全區 Stack address = 0x40196000//自己指定線程棧 Stack size = 0x201000 bytes//棧的大小
線程屬性這一塊,本文只是簡單列出,更深層次的掌握需要大家自行查閱資料。
線程的優缺點
線程的優點
- 創建一個線程的代價要比創建一個進程的代價小得多。
- 與進程之間的切換相比較,線程之間的切換操作系統要做的工作少得多。
- 線程占用的資源比進程少得多。
- 能充分利用 多處理器的可並行數量。
- 在等待慢速I/O操作結束時,程序可執行其他的計算任務。
- 計算密集型應用,多處理器運行,可以將計算分布到多個線程中計算。
- I/O密集型應用,為了提高性能,將I/O操作重疊,線程可以等待不同的I/O操作。
線程的缺點
- 性能損失
- 健壯性降低。
- 缺乏訪問控制
- 編程難度提高
- 多線程對GDB支持不好
- 多線程對信號支持不好
線程互斥
互斥量
互斥量
- 定義互斥鎖:pthread_mutex_t mutex;
- 初始化:pthread_mutex_init(&mutex,NULL);
- 上鎖:pthread_mutex_lock(&mutex);
- 解鎖:pthread_mutex_unlock(&mutex);
- 銷毀:pthread_mutex_destroy(&mutex);
自旋鎖
- 定義自旋鎖:pthread_spinlock_t spin;
- 初始化:int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
- 上鎖:int pthread_spin_lock(pthread_spinlock_t *lock);
- 解鎖:int pthread_spin_unock(pthread_spinlock_t *lock);
- 銷毀鎖:int pthread_spin_destroy(pthread_spinlock_t *lock);
自旋鎖與互斥鎖的區別
自旋鎖和互斥所的區別:互斥鎖是當阻在pthread_mutex_lock時,放棄CPU,好讓別人使用CPU。自旋鎖阻塞在spin_lock時,不會釋放CPU,不斷的問CPU可以使用了不
讀寫鎖
- pthread_rwlock_t lock;
- 初始化:int pthread_rwlock_init(pthread_rwlock_t restrict rwlock,const pthread_rwlockattr_t restrict attr);
- 讀鎖:int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
- 寫鎖:int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
- 解鎖:int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
- 銷毀鎖:int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
讀讀共享,讀寫排他,寫寫排他,寫鎖優先.
同步
條件變量
- 定義條件變量:pthread_cond_t cond;
- 初始化條件變量:int pthread_cond_init(pthread_cond_t restrict cond,const pthread_condattr_t restrict attr);
- 等待條件:int pthread_cond_wait(pthread_cond_t restrict cond,pthread_mutex_t restrict mutex);
如果沒有在鎖環境下使用,互斥量形同虛設
如果在鎖環境下,將mutex解鎖
wait返回時,將mutex置為原來的狀態 - 使條件滿足:int pthread_cond_signal(pthread_cond_t *cond);
- 銷毀條件變量:int pthread_cond_destroy(pthread_cond_t *cond);
綜合案例
pthread_mutex_t mutex;//創建互斥量
int a = 0;
int b = 0;
void *r1(void* arg) //線程1執行函數
{
while(1)
{
pthread_mutex_lock(&mutex);//上鎖
a++;
b++;
if(a != b)
{
printf("%d != %d\n",a,b);
}
pthread_mutex_unlock(&mutex);//解鎖
}
}
void *r2(void* arg)//線程2執行函數
{
while(1)
{
pthread_mutex_lock(&mutex);
a++;
b++;
if(a != b)
{
printf("%d != %d\n",a,b);
}
pthread_mutex_unlock(&mutex);
}
}
int main(void)
{
pthread_t t1,t2;
pthread_mutex_init(&mutex,NULL);//初始化互斥量
pthread_create(&t1,NULL,r1,NULL);//創建線程
pthread_create(&t2,NULL,r2,NULL);//創建線程
pthread_join(t1,NULL);//線程等待
pthread_join(t2,NULL);
return 0;
}
帶你學習多線程編程