⑴ pthread mutex放在共享內存中,可以跨進程使用么
創建的時候得調用
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);
其中 pshared 的值為 PTHREAD_PROCESS_SHARED
不過也得看 pthread 的版本,如果是 linuxthreads,則不支持
NPTL 則支持
⑵ linux mutex是可重入的嗎
函數原型:Int pthread_mutex_init(pthread_mutex_t *restrict_mutex,const pthread_mutextattr_t *restrict attr) 該函數主要用於多線程中互斥鎖的初始化。 如果attr為空的話,則是默認屬性,而默認屬性的快速互斥鎖。 pthread_mutex_init完成成功後會返回0,其他值都是錯誤的。 int pthread_mutextattr_destroy(pthread_mutextattr_t *restrict_mutext) 該函數是銷毀線程互斥鎖 設定互斥鎖的作用域: Int pthread_mutextattr_setpshared(pthread_mutexattr_t *restrict mutext, int pshared) 在多線程中是共享互斥鎖的。 如果想在多個進程中共享互斥鎖,可以把pshared設置PTHREAD_PROCESS_SHARED 如果只想在有同屬於一個進程創建的線程中共享互斥鎖,則可以把pshared設置為PTHREAD_PROCESS_PRIVATE 獲得互斥鎖的作用域: int pthread_mutexattr_getpshared(pthread_mutexattr_t *restrict mutext,int *pshared); 設定互斥鎖類型的屬性: int pthread_mutexattr_settype(pthread_mutexattr_t *restrict mutext,int type) 其中type類型都有: PTHREAD_MUTEX_NOMRAL:此類型的互斥鎖不會檢測死鎖 而其中的預設值值是PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_ERRORCHECK:是提供錯誤檢查 int pthread_mutexattr_setprotocal(pthread_mutexattr_t *attr,int protocal) protocal可以設置互斥鎖屬性的協議 PTHREAD_PRIO_NONE PTHREAD_PRIO_INHERIT PTHREAD_PRIO_PROTECT 作者舞者博客
⑶ Linux下線程同步的幾種方法
Linux 線程同步的三種方法
線程的最大特點是資源的共享性,但資源共享中的同步問題是多線程編程的難點。linux下提供了多種方式來處理線程同步,最常用的是互斥鎖、條件變數和信號量。
一、互斥鎖(mutex)
通過鎖機制實現線程間的同步。
初始化鎖。在Linux下,線程的互斥量數據類型是pthread_mutex_t。在使用前,要對它進行初始化。
靜態分配:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
動態分配:int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr_t *mutexattr);
加鎖。對共享資源的訪問,要對互斥量進行加鎖,如果互斥量已經上了鎖,調用線程會阻塞,直到互斥量被解鎖。
int pthread_mutex_lock(pthread_mutex *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
解鎖。在完成了對共享資源的訪問後,要對互斥量進行解鎖。
int pthread_mutex_unlock(pthread_mutex_t *mutex);
銷毀鎖。鎖在是使用完成後,需要進行銷毀以釋放資源。
int pthread_mutex_destroy(pthread_mutex *mutex);
[csharp] view plain
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <pthread.h>
#include "iostream"
using namespace std;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int tmp;
void* thread(void *arg)
{
cout << "thread id is " << pthread_self() << endl;
pthread_mutex_lock(&mutex);
tmp = 12;
cout << "Now a is " << tmp << endl;
pthread_mutex_unlock(&mutex);
return NULL;
}
int main()
{
pthread_t id;
cout << "main thread id is " << pthread_self() << endl;
tmp = 3;
cout << "In main func tmp = " << tmp << endl;
if (!pthread_create(&id, NULL, thread, NULL))
{
cout << "Create thread success!" << endl;
}
else
{
cout << "Create thread failed!" << endl;
}
pthread_join(id, NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
//編譯:g++ -o thread testthread.cpp -lpthread
二、條件變數(cond)
互斥鎖不同,條件變數是用來等待而不是用來上鎖的。條件變數用來自動阻塞一個線程,直到某特殊情況發生為止。通常條件變數和互斥鎖同時使用。條件變數分為兩部分: 條件和變數。條件本身是由互斥量保護的。線程在改變條件狀態前先要鎖住互斥量。條件變數使我們可以睡眠等待某種條件出現。條件變數是利用線程間共享的全局變數進行同步的一種機制,主要包括兩個動作:一個線程等待"條件變數的條件成立"而掛起;另一個線程使"條件成立"(給出條件成立信號)。條件的檢測是在互斥鎖的保護下進行的。如果一個條件為假,一個線程自動阻塞,並釋放等待狀態改變的互斥鎖。如果另一個線程改變了條件,它發信號給關聯的條件變數,喚醒一個或多個等待它的線程,重新獲得互斥鎖,重新評價條件。如果兩進程共享可讀寫的內存,條件變數可以被用來實現這兩進程間的線程同步。
初始化條件變數。
靜態態初始化,pthread_cond_t cond = PTHREAD_COND_INITIALIER;
動態初始化,int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
等待條件成立。釋放鎖,同時阻塞等待條件變數為真才行。timewait()設置等待時間,仍未signal,返回ETIMEOUT(加鎖保證只有一個線程wait)
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
激活條件變數。pthread_cond_signal,pthread_cond_broadcast(激活所有等待線程)
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond); //解除所有線程的阻塞
清除條件變數。無線程等待,否則返回EBUSY
int pthread_cond_destroy(pthread_cond_t *cond);
[cpp] view plain
#include <stdio.h>
#include <pthread.h>
#include "stdlib.h"
#include "unistd.h"
pthread_mutex_t mutex;
pthread_cond_t cond;
void hander(void *arg)
{
free(arg);
(void)pthread_mutex_unlock(&mutex);
}
void *thread1(void *arg)
{
pthread_cleanup_push(hander, &mutex);
while(1)
{
printf("thread1 is running\n");
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
printf("thread1 applied the condition\n");
pthread_mutex_unlock(&mutex);
sleep(4);
}
pthread_cleanup_pop(0);
}
void *thread2(void *arg)
{
while(1)
{
printf("thread2 is running\n");
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
printf("thread2 applied the condition\n");
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
int main()
{
pthread_t thid1,thid2;
printf("condition variable study!\n");
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_create(&thid1, NULL, thread1, NULL);
pthread_create(&thid2, NULL, thread2, NULL);
sleep(1);
do
{
pthread_cond_signal(&cond);
}while(1);
sleep(20);
pthread_exit(0);
return 0;
}
[cpp] view plain
#include <pthread.h>
#include <unistd.h>
#include "stdio.h"
#include "stdlib.h"
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
struct node
{
int n_number;
struct node *n_next;
}*head = NULL;
static void cleanup_handler(void *arg)
{
printf("Cleanup handler of second thread./n");
free(arg);
(void)pthread_mutex_unlock(&mtx);
}
static void *thread_func(void *arg)
{
struct node *p = NULL;
pthread_cleanup_push(cleanup_handler, p);
while (1)
{
//這個mutex主要是用來保證pthread_cond_wait的並發性
pthread_mutex_lock(&mtx);
while (head == NULL)
{
//這個while要特別說明一下,單個pthread_cond_wait功能很完善,為何
//這里要有一個while (head == NULL)呢?因為pthread_cond_wait里的線
//程可能會被意外喚醒,如果這個時候head != NULL,則不是我們想要的情況。
//這個時候,應該讓線程繼續進入pthread_cond_wait
// pthread_cond_wait會先解除之前的pthread_mutex_lock鎖定的mtx,
//然後阻塞在等待對列里休眠,直到再次被喚醒(大多數情況下是等待的條件成立
//而被喚醒,喚醒後,該進程會先鎖定先pthread_mutex_lock(&mtx);,再讀取資源
//用這個流程是比較清楚的
pthread_cond_wait(&cond, &mtx);
p = head;
head = head->n_next;
printf("Got %d from front of queue/n", p->n_number);
free(p);
}
pthread_mutex_unlock(&mtx); //臨界區數據操作完畢,釋放互斥鎖
}
pthread_cleanup_pop(0);
return 0;
}
int main(void)
{
pthread_t tid;
int i;
struct node *p;
//子線程會一直等待資源,類似生產者和消費者,但是這里的消費者可以是多個消費者,而
//不僅僅支持普通的單個消費者,這個模型雖然簡單,但是很強大
pthread_create(&tid, NULL, thread_func, NULL);
sleep(1);
for (i = 0; i < 10; i++)
{
p = (struct node*)malloc(sizeof(struct node));
p->n_number = i;
pthread_mutex_lock(&mtx); //需要操作head這個臨界資源,先加鎖,
p->n_next = head;
head = p;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mtx); //解鎖
sleep(1);
}
printf("thread 1 wanna end the line.So cancel thread 2./n");
//關於pthread_cancel,有一點額外的說明,它是從外部終止子線程,子線程會在最近的取消點,退出
//線程,而在我們的代碼里,最近的取消點肯定就是pthread_cond_wait()了。
pthread_cancel(tid);
pthread_join(tid, NULL);
printf("All done -- exiting/n");
return 0;
}
三、信號量(sem)
如同進程一樣,線程也可以通過信號量來實現通信,雖然是輕量級的。信號量函數的名字都以"sem_"打頭。線程使用的基本信號量函數有四個。
信號量初始化。
int sem_init (sem_t *sem , int pshared, unsigned int value);
這是對由sem指定的信號量進行初始化,設置好它的共享選項(linux 只支持為0,即表示它是當前進程的局部信號量),然後給它一個初始值VALUE。
等待信號量。給信號量減1,然後等待直到信號量的值大於0。
int sem_wait(sem_t *sem);
釋放信號量。信號量值加1。並通知其他等待線程。
int sem_post(sem_t *sem);
銷毀信號量。我們用完信號量後都它進行清理。歸還佔有的一切資源。
int sem_destroy(sem_t *sem);
[cpp] view plain
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
#define return_if_fail(p) if((p) == 0){printf ("[%s]:func error!/n", __func__);return;}
typedef struct _PrivInfo
{
sem_t s1;
sem_t s2;
time_t end_time;
}PrivInfo;
static void info_init (PrivInfo* thiz);
static void info_destroy (PrivInfo* thiz);
static void* pthread_func_1 (PrivInfo* thiz);
static void* pthread_func_2 (PrivInfo* thiz);
int main (int argc, char** argv)
{
pthread_t pt_1 = 0;
pthread_t pt_2 = 0;
int ret = 0;
PrivInfo* thiz = NULL;
thiz = (PrivInfo* )malloc (sizeof (PrivInfo));
if (thiz == NULL)
{
printf ("[%s]: Failed to malloc priv./n");
return -1;
}
info_init (thiz);
ret = pthread_create (&pt_1, NULL, (void*)pthread_func_1, thiz);
if (ret != 0)
{
perror ("pthread_1_create:");
}
ret = pthread_create (&pt_2, NULL, (void*)pthread_func_2, thiz);
if (ret != 0)
{
perror ("pthread_2_create:");
}
pthread_join (pt_1, NULL);
pthread_join (pt_2, NULL);
info_destroy (thiz);
return 0;
}
static void info_init (PrivInfo* thiz)
{
return_if_fail (thiz != NULL);
thiz->end_time = time(NULL) + 10;
sem_init (&thiz->s1, 0, 1);
sem_init (&thiz->s2, 0, 0);
return;
}
static void info_destroy (PrivInfo* thiz)
{
return_if_fail (thiz != NULL);
sem_destroy (&thiz->s1);
sem_destroy (&thiz->s2);
free (thiz);
thiz = NULL;
return;
}
static void* pthread_func_1 (PrivInfo* thiz)
{
return_if_fail(thiz != NULL);
while (time(NULL) < thiz->end_time)
{
sem_wait (&thiz->s2);
printf ("pthread1: pthread1 get the lock./n");
sem_post (&thiz->s1);
printf ("pthread1: pthread1 unlock/n");
sleep (1);
}
return;
}
static void* pthread_func_2 (PrivInfo* thiz)
{
return_if_fail (thiz != NULL);
while (time (NULL) < thiz->end_time)
{
sem_wait (&thiz->s1);
printf ("pthread2: pthread2 get the unlock./n");
sem_post (&thiz->s2);
printf ("pthread2: pthread2 unlock./n");
sleep (1);
}
return;
}
⑷ Linux線程喚醒多次
生產者產出數據到消費者獲得數據的延時較大,或者是CPU佔用較高。
生產者喚醒邏輯。pthread_mutex_lock(&mutex);pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);
條件變數的操作也需要達到線程安全的要求,因此需要互斥對象來進行保證。避免兩個線程同時操作條件變數引發問題。而通過查閱pthread_cond_wait()的相關資料可知,當程序運行到pthread_cond_wait()時,會將互斥對象鎖釋放,以便生產者能夠順利喚醒。而在消費者被成功喚醒,pthread_cond_wait()等待完成後,互斥對象會被重新上鎖直到手動釋放。
⑸ linux pthread 信號量 佔用資源嗎
glibc提供的pthread互斥信號量可以用在進程內部,也可以用在進程間,可以在初始化時通過pthread_mutexattr_setpshared介面設置該信號量屬性,表示是進程內還是進程間。進程內的使用較為簡單,本文的總結主要是針對進程間的,進程內的也可以參考,其代碼實現原理是類似的。
一、實現原理
pthread mutex的實現是非常輕量級的,採用原子操作+futex系統調用。
在沒有競爭的情況下,即鎖空閑時,任務獲取信號量只需要通過原子操作鎖的狀態值,把值置為佔有,再記錄其他一些俄信息(owner,計數,如果使能回收功能則串入任務的信號量回收鏈表等),然後就返回了。
如果在獲取鎖時發現被佔用了,如果調用者需要睡眠等待,這時候會觸發futex系統調用,由內核繼續處理,內核會讓調用任務睡眠,並在適當時候喚醒(超時或者鎖狀態為可用)。
佔用鎖的任務釋放鎖時,如果沒有任務等待這把鎖,只需要把鎖狀態置為空閑即可。如果發現有其他任務在等待此鎖,則觸發futex系統調用,由內核喚醒等待任務。
由此可見,在沒有競爭的情況下,mutex只需要在用戶態操作鎖狀態值,無須陷入內核,是非常高效的。
獲取到鎖的任務沒有陷入內核,那麼當鎖支持優先順序翻轉時,高優先順序任務等待這把鎖,正常處理必須提升佔用鎖的任務優先順序。內核又是怎麼知道是哪個任務佔用了鎖呢?實現上,復用了鎖的狀態值,該值在空閑態時為0,非空閑態則保存了鎖的持有者ID,即PID,內核態通過PID就知道是那個任務了。
二、內核對鎖的管理
內核維護了一個hash鏈表,每把鎖都被插入到hash鏈表中去,hash值的計算如下(參考get_futex_key):1,如果是進程內的鎖,則通
過鎖的虛擬地址+任務mm指針值+鎖在頁內偏移;2,如果是進程間的鎖,則會獲取鎖虛擬地址對應物理地址的page描述符,由page描述符構造
hash值。
這樣計算的原因是進程間的鎖在各個進程內虛擬地址可能是不同的,但都映射到同一個物理地址,對應同一個page描述符。所以,內
核使用它來定位是否同一個鎖。
這里對進程間互斥鎖計算hash值的方法,給進程間共享鎖的使用設置了一個隱患條件。下面描述這個問題。
三、進程間互斥信號量的使用限制:必須在系統管理的內存上定義mutex結構,而不能在用戶reserved的共享內存上定義mutex結構。
鎖要實現進程間互斥,必須各個進程都能看到這個鎖,因此,鎖結構必須放在共享內存上。
獲取系統的共享內存通過System V的API介面創建:shmget, shmat,shmdt。但是shmget的參數需要一個id值,各進程映射同一塊共享內存需要同樣的ID值。如果各個進程需要共享的共享內存比較多,如幾千上萬個,ID值如果管理?shmget的man幫助和一些示例代碼給出的是通過ftok函數把一個文件轉為ID值(實際就是把文件對應的INODE轉為ID值),但實際應用中,如果需要的共享內存個數較多,難道創建成千上萬個文件來使用?而且怎麼保證文件在進程的生命周期內不會被刪除或者重建?
當時開發的系統還存在另外一種共享內存,就是我們通過remap_pfn_range實現的,自己管理了這塊內存的申請釋放。申請介面參數為字元串,相同的字元串表示同一塊內存。因此,傾向於使用自己管理的共享內存存放mutex結構。但在使用中,發現這種方法達不到互斥的效果。為什麼?
原因是自己管理的共享內存在內核是通過remap_pfn_range實現的,內核會把這塊內存置為reserved,表示非內核管理,獲取鎖的HASH值時,查找不到page結構,返回失敗了。最後的解決方法還是通過shmget申請共享內存,但不是通過ftok獲取ID,而是通過字元串轉為ID值並處理沖突。
四、進程間互斥信號量回收問題。
假設進程P1獲取了進程間信號量,異常退出了,還沒有釋放信號量,這時候其他進程想來獲取信號量,能獲取的到嗎?
或者進程P1獲取了信號量後,其他進程獲取不到進入了睡眠後,P1異常退出了,誰來負責喚醒睡眠的進程?
好在系統設計上已經考慮了這一點。
只要在信號量初始化時調用pthread_mutexattr_setrobust_np設置支持信號量回收機制,然後,在獲取信號量時,如果原來佔有信號量的進程退出了,系統將會返回EOWNERDEAD,判斷是這個返回值後,調用pthread_mutex_consistent_np完成信號量owner的切換工作即可。
其原理如下:
任務創建時,會注冊一個robust list(用戶態鏈表)到內核的任務控制塊TCB中期,獲取了信號量時,會把信號量掛入鏈表。進程復位時,內核會遍歷此鏈表(內核必須非常小心,因為此時的鏈表信息可能不可靠了,可不能影響到內核),置上ownerdead的標志到鎖狀態,並喚醒等待在此信號量鏈表上的進程。
五、pthread介面使用說明
pthread_mutex_init: 根據指定的屬性初始化一個mutex,狀態為空閑。
pthread_mutex_destroy: 刪除一個mutex
pthread_mutex_lock/trylock/timedlock/unlock: 獲取鎖、釋放鎖。沒有競爭關系的情況下在用戶態只需要置下鎖的狀態值即返回了,無須陷入內核。但是timedlock的入參為超時時間,一般需要調用系統API獲取,會導致陷入內核,性能較差,實現上,可先trylock,失敗了再timedlock。
pthread_mutexattr_init:配置初始化
pthread_mutexattr_destroy:刪除配置初始化介面申請的資源
pthread_mutexattr_setpshared:設置mutex是否進程間共享
pthread_mutexattr_settype:設置類型,如遞歸調用,錯誤檢測等。
pthread_mutexattr_setprotocol:設置是否支持優先順序翻轉
pthread_mutexattr_setprioceiling:設置獲取信號量的任務運行在最高優先順序。
每個set介面都有對應的get介面。
六、pthread結構變數說明
struct __pthread_mutex_s
{
int __lock; ----31bit:這個鎖是否有等待者;30bit:這個鎖的owner是否已經掛掉了。其他bit位:0鎖狀態空閑,非0為持有鎖的任務PID;
unsigned int __count; ----獲取鎖的次數,支持嵌套調用,每次獲取到鎖值加1,釋放減1。
int __owner; ----鎖的owner
unsigned int __nusers; ----使用鎖的任務個數,通常為1(被佔用)或0(空閑)
int __kind;----鎖的屬性,如遞歸調用,優先順序翻轉等。
int __spins; ----SMP下,嘗試獲取鎖的次數,盡量不進入內核。
__pthread_list_t __list; ----把鎖插入回收鏈表,如果支持回收功能,每次獲取鎖時要插入任務控制塊的回收鏈表。
}__data;
⑹ linux線程同步的互斥鎖(mutex)到底怎麼用的》謝謝
互斥鎖(mutex) 通過鎖機制實現線程間的同步。
1、初始化鎖。在Linux下,線程的互斥量數據類型是pthread_mutex_t。在使用前,要對它進行初始化。
2、靜態分配:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
3、動態分配:int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr_t *mutexattr);
4、加鎖。對共享資源的訪問,要對互斥量進行加鎖,如果互斥量已經上了鎖,調用線程會阻塞,直到互斥量被解鎖。
intpthread_mutex_lock(pthread_mutex*mutex);
intpthread_mutex_trylock(pthread_mutex_t*mutex);
解鎖。在完成了對共享資源的訪問後,要對互斥量進行解鎖。
intpthread_mutex_unlock(pthread_mutex_t*mutex);
銷毀鎖。鎖在是使用完成後,需要進行銷毀以釋放資源。
intpthread_mutex_destroy(pthread_mutex*mutex);
#include<cstdio>
#include<cstdlib>
#include<unistd.h>
#include<pthread.h>
#include"iostream"
usingnamespacestd;
pthread_mutex_tmutex=PTHREAD_MUTEX_INITIALIZER;
inttmp;
void*thread(void*arg)
{
cout<<"threadidis"<<pthread_self()<<endl;
pthread_mutex_lock(&mutex);
tmp=12;
cout<<"Nowais"<<tmp<<endl;
pthread_mutex_unlock(&mutex);
returnNULL;
}
intmain()
{
pthread_tid;
cout<<"mainthreadidis"<<pthread_self()<<endl;
tmp=3;
cout<<"Inmainfunctmp="<<tmp<<endl;
if(!pthread_create(&id,NULL,thread,NULL))
{
cout<<"Createthreadsuccess!"<<endl;
}
else
{
cout<<"Createthreadfailed!"<<endl;
}
pthread_join(id,NULL);
pthread_mutex_destroy(&mutex);
return0;
}
//編譯:g++-othreadtestthread.cpp-lpthread
⑺ 有人能教下我有關linux裡面線程的知識嗎
.線程的基本介紹
(1)線程的概述
線程與進程類似,也允許應用程序並發執行多個任務的一種機制。一個進程可以包含多個線程,同一程序中的所有線程共享同一份全局內存區域,線程之間沒有真正意義的等級之分。同一個進程中的線程可以並發執行,如果處理器是多核的話線程也可以並行執行,如果一個線程因為等待I/O操作而阻塞,那麼其他線程依然可以繼續運行
(2)線程優於進程的方面
argv,environ
主線程棧
線程3的棧
線程2的棧
線程1的棧
共享函數庫共享的內存
堆
未初始化的數據段
初始化數據段
文本
.進程間的信息難以共享。由於除去只讀代碼段外,父子進程並未共享內存,因此必須採用一些進程間通訊,在進程之間交換信息
.調用fork()來創建進程代價相對較高
線程很好的解決了上述倆個問題
.線程之間能夠方便,快速的共享信息,只需將數據復制到共享(全局或堆)變數中即可
.創建線程比創建線程通常要快10甚至更多,線程創建之所以快,是因為fork創建進程時所需復制多個屬性,而在線程中,這些屬性是共享的。
(3)創建線程
啟動程序時,產生的進程只有單條線程,我們稱之為主線程
#include<pthread.h>
int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void*(*start)(void *),void *arg);12
新線程通過調用帶有arg的函數開始執行,調用pthread_create()的線程會繼續執行該調用之後的語句。
(4)終止線程
可以以如下方式終止線程的運行
.線程調用pthread_exit()
.線程start函數執行return語句並返回指定值
.調用pthread_cancel()取消線程
.任意線程調用了exit(),或者主線程執行了return語句,都會導致進程中的所有線程立即終止
pthread_exit()函數可以終止線程,且其返回值可由另一線程通過調用pthread_join()獲得
#include<pthread.h>void pthread_exit(void *retval);12
調用pthread_exit()相當於在線程的start函數中執行return,不同之處在於,pthread_exit()可以在任何地方調用,參數retval指定了線程的返回值
(5)獲取線程ID
#include<pthread.h>pthread_t pthread_self(void);12
線程ID在應用程序中主要有如下用途
.不同的pthreads函數利用線程ID來標識要操作目標線程。
.在具體的應用程序中,以特定線程的線程ID作為動態數據結構的標簽,這頗有用處,既可用來識別某個數據結構的創建者或屬主線程,又可確定隨後對該數據結構執行操作的具體線程
函數pthread_equal()可檢查倆個線程的ID是否相同
#include<pthread.h>int pthread_equal(pthread_t t1,pthread_t t2);//如果相同返回非0值,否則返回0123
(6)連接已終止的線程
函數pthread_join()等待由thread表識的線程終止
#include<pthread.h>int pthread_join(pthread_t thread,void **retval);//返回0調用成功,否則失敗123
如果pthread_join()傳入一個之前已然連接過的線程ID,將會導致無法預知的行為,當相同線程ID在參與一次連接後恰好為另一新建線程所重用,再度連接的可能就是這個新線程
若線程未分離,則就應該使用pthread_join()來連接線程,否則會產生僵屍線程
pthrea_join()函數的要點
.線程之間的關系是對等的,所以任意線程都可以調用pthread_join()來連接其他線程
.pthread_join()無法針對任意線程,只能連接單個線程
(6)線程的分離
默認情況下線程都是可連接的,但有時候,我們並不關心線程退出的狀態,我們可以調用pthread_detach()並向thread參數傳入指定線程的的標識符,將該線程標記為處於分離狀態
#include<pthread.h>int pthread_detach(pthread_t thread);//返回0成功,否則失敗123
一旦線程處於分離狀態,就不能在使用pthread_join()來獲取其狀態,也無法使其重返可連接狀態
(7)在應用程序中如何來選擇進程還是線程
.線程之間共享數據很簡單,進程間的數據共享需要更多的投入
.創建線程要比創建進程塊很多
.多線程編程時,需要確保調用線程安全的函數
.某個線程中的bug可能會危害進程中所有線程
.每個線程都在徵用宿主進程中有限的虛擬地址空間
.在多線程應用中,需要小心使用信號
.除了數據,線程還可以共享文件描述符,信號處置,當前工作目錄,以及用戶ID和組ID
線程的同步
(1)保護共享變數訪問:互斥量
線程的主要優勢在於能夠通過全局變數來共享信息,不過這種共享是有代價的。必須確保多個線程修改同一變數時,不會有其他線程也正在修改此變數,為避免線程更新時共享變數時所出現的問題,必須使用互斥量來確保同時僅有一個線程可以訪問某項共享資源
(2)靜態分配的互斥鎖
互斥鎖既可以像靜態變數那樣分配,也可以在運行時動態分配,互斥量屬於pthread_mutex_t類型的變數,在使用之前必須對其初始化。對於靜態分配的互斥量而言,可如下例所示,將PTHREAD_MUTEX_INITIALIZER賦給互斥量
pthread_mutex_t = PTHREAD_MUTEX_INITIALIZER;1
1.加鎖和解鎖互斥量
初始化之後,互斥量處於未鎖定狀態。函數pthread_mutex_lock()可以鎖定某一互斥量
而函數pthread_mutex_unlock()則可以將一個互斥量解鎖
#include<pthread.h>int pthread_mutex_lock(pthread_mutex_t *mutex);int pthread_mutex_unlock(pthread_mutex_t *mutex);//返回0成功,其他失敗1234
要鎖定互斥量,在調用pthread_mutex_lock()時需要指定互斥量,如果互斥量當前處於未鎖定狀態,則該調用將會立即返回,如果該互斥量已被其他線程鎖定,那麼該調用將會阻塞,直至互斥量被解鎖
函數pthread_mutex_unlock()將解鎖之前已遭調用線程鎖定的互斥量
2.互斥量的性能
通常情況下,線程會花費更多的時間去做其他工作,對互斥量的加鎖解鎖相對要少的多,因此使用互斥量對大部分程序來說性能並無顯著的影響
3.互斥量的死鎖
當一個線程需要同時訪問多個共享資源時,沒個資源由不同的互斥索管理。當超過一個線程加鎖同一組互斥量時,就有可能發生死鎖。如下圖所示
線程A
1.pthread_mutex_lock(mutex1);
2.pthread_mutex_lock(mutex2);
線程2
1.pthread_mutex_lock(mutex2);
2.pthread_mutex_lock(mutex1);
每個線程都成功的鎖住一個互斥量,接著試圖對以為另一線程鎖定的互斥量加鎖,就會一直等下去
要避免此類死鎖問題,最簡單的就是定義互斥量的層級關系
⑻ linux下互斥鎖mutex,貌似鎖不上呢
多線程的效果就是同一時間各個線程都在執行。
加鎖不是給線程上鎖。
pthread_mutex_lock(&qlock);表示嘗試去把qlock上鎖,它會先判斷qlock是否已經上鎖,如果已經上鎖這個線程就會停在這一步直到其他線程把鎖解開。它才繼續運行。
所以代碼中要麼是線程1先執行完後執行線程2,要麼就是線程2先執行,再執行線程1.而線程3一開始就執行了。
互斥量mutex是用來給多線程之間的貢獻資源上鎖的。也就是同一個時間只允許一個線程去訪問該資源(資源:比如對文件的寫操作)。
現在來回答樓主的問題:
不是只要在pthread_mutex_lock(&qlock)與pthread_mutex_unlock(&qlock)之間的代碼執行,其他的都不能介入嗎?
其他的都不能介入,不是整個進程只運行這一個線程,其他線程都停住了。
「不能介入「這個動作需要程序員自己設計來保證:好比前面提到的文件讀寫操作。為了防止多個線程同時對文件進行寫入操作,這就需要把資源上鎖了。
如果只有線程1加鎖,那是不是這個鎖就沒有意義了呢?
這個理解可以有
⑼ Linux C語言pthread_mutex_unlock和pthread_cond_signal順序問題
signal前解鎖是錯誤,順序相當重要,鎖才能保證你整個操作是完全原子,signal只是整個操作的一部分,它不能被分割出去。用特殊一點的情況來解釋:如果解鎖後才signal,那麼有可能信號一直發不出去,因為信號線程一直得到不調度。