線程函數(shù)
int pthread_equal(pthread_t tid1, pthread_t tid2)
pthread_t pthread_self(void)
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr
void* (*start_rtn)(void), void* restrict arg)
thread被創(chuàng)建的時候會繼承調(diào)用線程的浮點環(huán)境和信號屏蔽字,但是該線程的未決信號集將會被清楚,
清除未決信號集這件事情應該是沒有疑問的,在thread創(chuàng)建之前pending住的信號,不應該deliver給下一個
Ps: 線程的浮點環(huán)境指的是啥? 看來以后我應該去注意下浮點數(shù)的運算原理。
pthread相關的函數(shù)會直接返回錯誤碼,而不會和一些system call一樣,置全局errno,兩種方式都有好處,一個可以講返回值
帶回的錯誤代碼集中起來,范圍縮小;另外一個非常方便,關鍵點在于這一類共用errno的是否真的異常是可以共用的。
pthread_create返回之前有可能新的線程就已經(jīng)開始run了
啟動函數(shù) void* (*start_rtn)(void)
可以通過return給回來,也可以通過pthread_exit給
這個會存在一個地方
通過pthread_join(tid, void**)取回來
這里join的和java join是一樣的功能
如果這個東西是一個很大的東西:),那么放到heap是最好的選擇,不要放到stack上了,不然線程返回這東西就沒了,join取到的內(nèi)存地址就變成一個無效的了,SIGSEGV就會被發(fā)出來
pthread_cancel,同一個進程可以call,提出請求終止線程
pthread_cleanup_push
pthread_cleanup_pop
線程分離,這樣子線程終止后可以釋放一些資源,而不用一定要其他人來join
方法有兩種,新建的時候加上分離屬性
pthread_attr_init (&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
或者call pthread_detach(pthread_t tid)
線程互斥與同步
typedef struct


{
int volatile value;
} pthread_mutex_t;


多注意volatile變量,這個東西理論上就是讓編譯器不要做優(yōu)化,不要cache volatile類型的變量,
每次都去內(nèi)存地址中拿,而不是寄存器/高速緩存副本,這種變量極容易被編譯器不知道的人改變,例如其他線程。
靜態(tài)初始化:
#define PTHREAD_MUTEX_INITIALIZER {0}
#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER {0x4000}
#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER {0x8000}
所謂的動態(tài)初始化
pthread_mutex_init; pthread_mutex_destroy
然后就是一些pthread mutex的基本處理函數(shù)了
lock,unlock
trylock;
這個trylock需要好好理解下,嘗試獲取lock,如果OK,那么lock他然后 return 0; 否則也不會suspend住,而是直接返回EBUSY
pthread_mutex_destroy, 會先去try lock,然后處理掉這個mutex的值。
這里稍微提一下
int pthread_mutex_trylock(pthread_mutex_t *mutex)


{
int mtype, tid, oldv, shared;

if (__unlikely(mutex == NULL))
return EINVAL;

mtype = (mutex->value & MUTEX_TYPE_MASK);
shared = (mutex->value & MUTEX_SHARED_MASK);


/**//* Handle common case first */
if ( __likely(mtype == MUTEX_TYPE_NORMAL) )

{

if (__atomic_cmpxchg(shared|0, shared|1, &mutex->value) == 0)
{
ANDROID_MEMBAR_FULL();
return 0;
}

return EBUSY;
}





__likely/__unlikely函數(shù)用來告訴編譯器優(yōu)化代碼,類似if else中最有可能or最沒有可能發(fā)生的Case
mutex就有deadlock的問題,單線程,如果有代碼重入重復獲取鎖就會deadlock,因為你走不到你unlock的地方去;另外
常見的deadlock就是lock比較多,又沒有設計好順序,這個應該從業(yè)務邏輯上就應該定義好,當然有時候有的人用的時候or改代碼的時候
并沒有理清這些lock的關系,是否有dependency,比較難通過借用一些編譯系統(tǒng)來Cover住,然后改完就有bug。
然后還有一種需要設計好的是鎖的粒度
太粗太細都不好
粒度太粗,lock住的東西太多,很多線程都要等lock,最后這個東西會演變成一個串行的東西
粒度太細,lock又變的太多,不停的需要lock/unlock,performance就會變差。
目前看到的Android上的很多l(xiāng)ock都太粗。
rw鎖 ->讀寫鎖
基本理念就是讀不會影響臨界區(qū)發(fā)生變化
所以讀模式的rw lock可以多個人占用,寫模式的rw lock時能被一個線程lock
只要有寫模式lock請求,那么后面的讀模式lock請求一般實現(xiàn)是都會被Suspend住,不然因為讀模式下,可以重復lock,如果不
suspend,那么寫模式的lock請求有可能永遠得不到相應。
rw鎖一般用在 read比 write行為多的多的場景,允許多線程并發(fā)去讀,單一線程去寫。
然后會想到spinlock,可以去網(wǎng)上search看下基本概念,spinlock一般在SMP架構(gòu)下會比較有效果。
mutex是一種同步機制or講這是一種互斥機制 -> Java synchronize
還一種就是條件變量 condition.. -> wait/notify
這里有段話很好
條件變量給多個線程提供了一個回合的場所,條件變量與互斥量一起使用的時候,允許線程以無競爭方式等待特定的條件發(fā)生。
作業(yè):
1.線程之間傳遞數(shù)據(jù)不要用stack變量,用放到下面這些地方的變量就好,RW/RO/ZI/Heap就沒事了
4.
現(xiàn)在一般都是這樣
pthread_mutex_lock(&s_startupMutex);
s_started = 1;
pthread_cond_broadcast(&s_startupCond);
pthread_mutex_unlock(&s_startupMutex);
會在broadcast后才unlock
否則有比較高的概率,unlock后,被其他線程將條件改掉,這個時候broadcast出去就沒有意義了。
但是這種也有可能會被另外一個線程,并非wait在那里的線程改變條件值
所以 pthread_cond_wait 返回并不意味著條件一定為真了
最好是always check條件
類似這種
while (s_started == 0) {
pthread_cond_wait(&s_startupCond, &s_startupMutex);
}