linux多线程和锁
要內容:?
第一部分 多線程?
第二部分 互斥鎖?
第三部分 條件變量?
第四部分 讀寫鎖?
第五部分 自旋鎖?
第六部分 線程壁壘?
第七部分 記錄鎖
?
??
第一部分 多線程
??
Linux 線程的創建:?
int pthread_create ( pthread_t *tid, const pthread_attr_t *attr, void *(*func) (void *), void *arg);?
tid:返回的線程id?
attr:創建線程的屬性可以為NULL,也可以在運行時再改變?
func:線程運行的callback函數?
arg:傳給callback函數的參數?
主要屬性簡要說明:?
PTHREAD_CREATE_DETACH :表示同步脫離,且在退出時自行釋放所占用的資源, 此時線程不能用pthread_join()來同步,這個屬性可以在線程運行時調用pthread_detach()來設置,而一旦設置為PTHREAD_CREATE_DETACH狀態(不論是創建時設置還是運行時設置)則不能再恢復到PTHREAD_CREATE_JOINABLE(默認屬性)狀態。?
int pthread_detach (pthread_t tid);?
說明:線程默認終止的時候資源不釋放需要主進程調用pthread_join函數才能釋放(類似于僵死進程和waitpid函數), pthread_detach 使得線程終止即釋放資源,主進程不需要調用pthread_join函數?
??
線程退出情形:?
1) 正常return退出?
2) 被其它線程調用pthread_cancel取消?
3) 調用pthread_exit 退出,其中參數為函數退出時返回的數據?
int pthread_join (pthread_t thread, void **rval_ptr);?
阻塞直到指定線程終止, 并返回線程的返回值。?
注意pthread_join函數操作的線程必須不是DETACHED線程。?
rval_ptr返回值設置:?
1) 如果線程正常return,則設置為return的值?
2) 如果線程被取消則設置為PTHREAD_CANCELED?
3) 如果線程調用pthread_exit退出則為pthread_exit 的參數?
退出函數設置:?
當線程退出時,可以設置一組退出函數類似于進程的atexit?
void pthread_cleanup_push (void (*rtn)(void *),?? void *arg);?
void pthread_cleanup_pop (int execute);?
退出函數執行條件:?
1) 線程調用pthread_exit 退出?
2) 線程被其它線程取消?
3) 調用pthread_cleanup_pop 并且參數非0?
注意:函數正常return 不調用退出函數?
??
線程的取消:?
int pthread_cancel (pthread_t tid);發送終止信號給thread線程,如果成功則返回0,否則為非0值。發送成功并不意味著thread會終止 .?
int pthread_setcancelstate (int state, int *oldstate)?
設置本線程對cancel信號的反應.?
state有兩種值:?
1)PTHREAD_CANCEL_ENABLE(缺省)收到信號后設為CANCLED狀態2)PTHREAD_CANCEL_DISABLE,忽略CANCEL信號繼續運行?
old_state如果不為NULL則存入原來的cancel狀態以便恢復。?
int pthread_setcanceltype (int type, int *oldtype)?
設置本線程取消動作的執行時機,僅當cancel狀態為Enable時有效?
type由兩種取值:?
1) PTHREAD_CANCEL_DEFFERED表示收到信號后繼續運行至下一個取消點再退出?
2) PTHREAD_CANCEL_ASYCHRONOUS表示立即執行取消動作(退出);?
oldtype如果不為NULL則存入原來的取消動作類型值。?
void pthread_testcancel (void)?
檢查本線程是否處于canceld狀態,如果是,則執行取消動作,否則直接返回。?
此函數用來設置取消點
??
線程私有數據(Thread-specific Data,或TSD)?
int pthread_key_create (pthread_key_t *keyptr, void (*destructor) (void *value));?
該函數從TSD池中分配一項,將其值賦給keyptr供以后訪問使用。如果destr_function不為空,在線程退出(pthread_exit())時將以key所關聯的數據為參數調用destr_function(),以釋放分配的緩沖區。?
int pthread_key_delete (pthread_key_t key)這個函數并不檢查當前是否有線程正使用該TSD,也不會調用清理函數,而只是將TSD釋放以供下一次調用pthread_key_create()使用。?
TSD的讀寫:?
int pthread_setspecific (pthread_key_t key, const void *pointer)?
寫入,將pointer的值(不是所指的內容)與key相關聯?
void * pthread_getspecific (pthread_key_t key)?
讀出函數,將與key相關聯的數據讀出來。?
說明:不同線程對同一個key的訪問互不沖突。?
??
pthread_once_t initflag = PTHREAD_ONCE_INIT;?
int pthread_once (pthread_once_t *initflag, void? (*initfn)(void));?
多個線程調用,保證僅執行一次的函數,其中initflag不可以是局部變量。?
獲得線程本身id?
pthread_t pthread_self (void);?
線程id 比較int pthread_equal (pthread_t tid1, pthread_t tid2); 相等返回非0?
??
線程IO操作:?
如果多個線程并發訪問同一個文件的時候可以使用pread或pwrite它們保證了原子操作?
其它:?
pthread_kill_other_threads_np() 強行殺死所有線程,它沒有通過pthread_cancel()來終止線程,而是直接向管理線程發“進程退出”信號,使所有其他線程都結束運行,而不經過cancel動作,當然也不會執行退出回調函數 ,一般用在exec執行前來結束所有正在運行的線程。?
線程屬性操作(略)?
??
第二部分 互斥鎖
??
Mutex基本操作函數:?
初始化方法:?
?1)? 如:static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER 使用默認屬性?
?2)? 調用pthread_mutex_init 方法,可以同時設定屬性?
銷毀方法:?
int pthread_mutex_destroy (pthread_mutex_t *mutex);?
銷毀一個互斥鎖即釋放它所占用的資源,并且要求鎖當前是非鎖定狀態。由于在Linux中,互斥鎖并不占用任何資源,它除了檢查鎖狀態以外(鎖定狀態則返回EBUSY)沒有其它動作。?
互斥鎖基本操作:?
int pthread_mutex_lock (pthread_mutex_t *mutex);?
int pthread_mutex_trylock (pthread_mutex_t *mutex);?
int pthread_mutex_unlock (pthread_mutex_t *mutex);?
??
Mutex基本屬性操作:?
int pthread_mutexattr_init (pthread_mutexattr_t *attr);?
int pthread_mutexattr_destroy (pthread_mutexattr_t?? *attr);?
int pthread_mutexattr_getpshared (const?? pthread_mutexattr_t * restrict attr, int *restrict?? pshared);?
int pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared);?
說明:?
1) Mutex默認只能用于多線程間互斥操作即屬性為PTHREAD_PROCESS_PRIVATE ,如果用于多進程操作必須修改其屬性為PTHREAD_PROCESS_SHARED?
2) pthread_mutexattr_init 和 pthread_mutexattr_destroy 函數用來初始化或析構pthread_mutexattr_t 結構 但由另外兩個函數來設置PTHREAD_PROCESS_SHARED 屬性?
3) 注意有些平臺不支持多進程間互斥鎖.?
其它屬性簡要介紹:?
1) PTHREAD_MUTEX_TIMED_NP: 普通鎖(缺省值)。當一個線程加鎖以后,其余請求鎖的線程將形成一個等待隊列,并在解鎖后按優先級獲得鎖。這種鎖策略保證了資源分配的公平性。?
2) PTHREAD_MUTEX_RECURSIVE_NP:嵌套鎖,允許同一個線程對同一個鎖成功獲得多次,并通過多次unlock解鎖。如果是不同線程請求,則在加鎖線程解鎖時重新競爭?
3) PTHREAD_MUTEX_ERRORCHECK_NP: 檢錯鎖,如果同一個線程請求同一個鎖,則返回EDEADLK,否則與PTHREAD_MUTEX_TIMED_NP類型動作相同。這樣就保證當不允許多次加鎖時不會出現最簡單情況下的死鎖?
4) PTHREAD_MUTEX_ADAPTIVE_NP,適應鎖,僅等待解鎖后重新競爭。?
??
使用互斥鎖注意事項:?
1) Linux 中實現的POSIX線程鎖都不是取消點,因此,線程被取消后不會因為收到取消信號而離開加鎖等待狀態。?
2) 如果線程在加鎖后解鎖前被取消,鎖將永遠保持鎖定狀態,因此如果在關鍵區段內有取消點存在,或者設置了異步取消類型,則必須在退出回調函數中解鎖。?
3) 這個鎖機制同時不是異步信號安全的,所以不應該在信號處理函數中使用互斥鎖,否則容易造成死鎖。?
??
第三部分 條件變量?
??
條件變量主要的目的是等待直到條件成立。類似于某些系統的Event。?
它主要包括兩個動作:?
1)? 一個線程等待“條件變量的條件成立”而掛起;?
2) 另一個線程使“條件成立”。?
注意:為了防止競爭條件變量的使用總是和一個互斥鎖結合在一起?
??
條件變量基本操作函數:初始化方法:?
?1)? 如:static pthread_cond_t? cond=PTHREAD_COND_INITIALIZER默認屬性?
?2)? 調用pthread_cond_init 方法,可以同時設定屬性?
銷毀方法:?
int pthread_cond_destroy (pthread_cond_t *cond);?
只有在沒有線程在該條件變量上等待的時候才能注銷這個條件變量,否則返回EBUSY。?
等待操作:?
int pthread_cond_wait (pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex)?
int pthread_cond_timedwait (pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict timeout);?
產生信號操作:?
int pthread_cond_signal (pthread_cond_t *cond);激活一個等待該條件的線程,存在多個等待線程時按入隊順序激活其中一個?
int pthread_cond_broadcast (pthread_cond_t *cond);激活所有等待線程?
??
屬性基本操作(類似于互斥鎖)?
int pthread_condattr_init (pthread_condattr_t *attr);?
int pthread_condattr_destroy (pthread_condattr_t?? *attr);?
int pthread_condattr_getpshared (const?? pthread_condattr_t * restrict attr, int *restrict?? pshared);?
int pthread_condattr_setpshared (pthread_condattr_t?? *attr, int pshared);?
??
使用條件變量注意事項:?
1) pthread_cond_wait()和pthread_cond_timedwait()都被實現為取消點, 在該處等待的線程將立即重新運行 2) 被取消后它首先獲的互斥鎖,然后執行取消動作。即互斥鎖是保持鎖定狀態的,因而需要定義退出回調函數來為其解鎖。?
使用舉例:?
{?
pthread_mutex_lock (&mutex));?
pthread_cond_wait (&cond,& mutex);?
pthread_mutex_unlock (&mutex);?
}?
?
第四部分 讀寫鎖?
??
讀寫鎖基本特點:?
1)如果沒有線程持有寫鎖, 那么獲得讀鎖就會成功?
2)如果沒有線程持有讀鎖和寫鎖,那么獲得寫鎖才會成功?
它常被應用于頻繁讀而很少修改得情況。?
??
讀寫鎖初始化或銷毀:?
static pthread_rwlock_t rwLock = PTHREAD_RWLOCK_INITIALIZER?
int pthread_rwlock_init (pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t? *restrict attr);?
int pthread_rwlock_destroy (pthread_rwlock_t *rwlock);?
獲得鎖或釋放鎖操作?
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_tryrdlock (pthread_rwlock_t?? *rwlock);?
int pthread_rwlock_trywrlock (pthread_rwlock_t?? *rwlock);?
屬性設置?
int pthread_rwlockattr_init (pthread_rwlockattr_t?? *attr);?
int pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr);?
int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * restrict attr, int *restrict pshared);?
int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared);?
??
第五部分 自旋鎖
??
自旋鎖基本特點:?
1) 在用戶空間實現, 不需要做內核切換?
2) 忙-等待,也就是說在獲得不了鎖的情況下仍然占用CPU資源?
3) 要求關鍵區域執行時間必須非常得短小,并且不允許睡眠, 如果執行時間超過了其它線程等待的時間片(即時間片用完,發生了線程切換), 則用自旋鎖就失去了意義,并空耗了CPU時間, 這種情況不防稱為失敗的等待
4) 如果失敗的等待非常多會嚴重影響系統的性能。此時就應該選用其它鎖?
??
基本操作函數:?
1) 初始化方法: __pshared大于0表示用在多進程間?
? int pthread_spin_init (pthread_spinlock_t *__lock, int __pshared)?
2)銷毀方法:?
int pthread_spin_destory (pthread_spinlock_t * __lock)?
3) 鎖操作方法:?
int? pthread_spin_lock (pthread_spinlock_t * __lock)?
int? pthread_spin_trylock (pthread_spinlock_t * __lock)?
int? pthread_spin_unlock (pthread_spinlock_t * __lock)?
??
第六部分 線程壁壘?
??
壁壘(barrier)基本說明:?
主要用來等待某些數量的線程在壁壘處集合。在設定的數目達到之后,解鎖這些線程,讓它們繼續運行。?
而pthread_join() 方法是等待線程結束?
??
壁壘(barrier)基本操作函數:?
初始化: count表示必須調用pthread_barrier_wait線程的個數?
int pthread_barrier_init (pthread_barrier_t? *barrier, const pthread_barrierattr_t *attr, unsigned int count);?
銷毀函數:?
int pthread_barrier_destroy (pthread_barrier_t *barrier)?
同步點函數:?
int pthread_barrier_wait (pthread_barrier_t *barrier);?
??
第七部分 記錄鎖
??
記錄鎖主要用于不同進程間鎖定文件,它可以鎖定整個文件或部分字節數據?
注意:記錄鎖是面向進程的,因此不能用于線程間。?
主要操作函數如下:?
int fcntl (int filedes, int cmd, ... /* struct?? flock *flockptr */ );?
其中:?
struct flock?
{?
? short l_type; /* F_RDLCK(共享讀), F_WRLCK(排斥寫), F_UNLCK(解鎖) */?
? off_t l_start; /* 相對于l_whence的偏移(字節單位) */?
? short l_whence; /* SEEK_SET, SEEK_CUR, or SEEK_END */?
?? off_t l_len; /* 鎖定長度,0表示鎖定到文件結束 */?
?? pid_t l_pid; /* 用于 F_GETLK */?
};?
cmd:?
F_GETLK: 獲得鎖狀態?
F_SETLK: 非阻塞獲得鎖失敗返回EAGAIN?
F_SETLKW: 阻塞獲得鎖, 可被信號喚醒。?
??
記錄鎖用法說明:?
1) 當進程終止或關閉描述符的時候,鎖自動釋放。?
?a.?? fd1 = open (pathname, ...);??????? b.? fd1 = open (pathname, ...);?
?????? read_lock(fd1, ...);?????????????????????????? read_lock(fd1, ...);?
?????? fd2 = dup(fd1);???????????????????????????????? fd2 = open (pathname, ...)?
?????? close(fd2);??????????????????????????????????????? close(fd2);?
2) 當fork子進程的時候,鎖不被繼承。?
3) 當執行exec的時候鎖不釋放。設置了close-on-exec的除外?
4) 有Advisory和Mandatory鎖?
??? 系統中默認是Advisory鎖, 當一個進程獲得鎖進行讀寫的時候,并不能阻止其它進行不去獲得鎖直接進行讀寫, 為了保證操作的正確性, 所有操作文件的進程必須按照規則, 首先獲得鎖 然后才能進行讀寫。?
?? Mandatory 鎖保證了當一個進程獲得鎖進行讀寫得時候, 其它進行直接讀寫文件會失敗。
總結
以上是生活随笔為你收集整理的linux多线程和锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 看框架总结
- 下一篇: makefile文件简要介绍