新聞中心
隨著計算機(jī)系統(tǒng)的不斷提升,多核CPU逐漸成為高性能計算機(jī)的核心部分,多線程編程也逐漸成為軟件開發(fā)領(lǐng)域的熱門技術(shù)之一。在多線程編程中,線程同步是一個必不可少的操作,而linux c多線程同步技術(shù)是實(shí)現(xiàn)線程同步的關(guān)鍵。

本文將圍繞Linux C多線程同步技術(shù)展開深入解析,主要包括以下幾個方面:多進(jìn)程同步機(jī)制、多線程同步機(jī)制、pthread庫的使用、互斥鎖、條件變量、信號量等內(nèi)容。
一、多進(jìn)程同步機(jī)制
在Linux操作系統(tǒng)中,多進(jìn)程之間的通信和同步涉及到諸多機(jī)制,例如管道、socket、消息隊列、共享內(nèi)存等。其中,共享內(nèi)存是一種特殊的內(nèi)存區(qū)域,可以被多個進(jìn)程進(jìn)行訪問,從而實(shí)現(xiàn)進(jìn)程之間的通信和同步。
共享內(nèi)存是一種直接通信機(jī)制,因為進(jìn)程可以直接訪問共享內(nèi)存,而不需要進(jìn)行系統(tǒng)調(diào)用。同時,共享內(nèi)存機(jī)制提供了一些同步機(jī)制,例如信號量、互斥鎖等,可用于控制進(jìn)程之間對共享內(nèi)存數(shù)據(jù)的訪問順序。
二、多線程同步機(jī)制
Linux操作系統(tǒng)中,線程同步也涉及到各種機(jī)制,例如進(jìn)程間通信機(jī)制、互斥鎖、條件變量、信號量等。
在多線程編程中,互斥鎖是最常用的同步機(jī)制之一,用于控制對共享資源的訪問。具體來說,互斥鎖在對某一共享資源進(jìn)行操作時,先加鎖,操作完成后再釋放鎖,從而保證同一時刻只有一個線程對共享資源進(jìn)行訪問,避免了多個線程同時修改共享資源,從而導(dǎo)致數(shù)據(jù)不一致的問題。
此外,條件變量用于線程間的等待和通知。一般情況下,條件變量和互斥鎖一起使用,因為鎖能夠保證線程間的互斥操作,而條件變量則提供了一種線程間的等待和通知機(jī)制。
信號量是一種機(jī)制,用于控制對一組共享資源的訪問。當(dāng)一個線程需要進(jìn)行對共享資源的訪問時,它請求信號量,如果信號量的計數(shù)器大于0,那么線程就可以訪問共享資源,同時信號量的計數(shù)器將減一。如果信號量計數(shù)器為0,那么線程將處于等待狀態(tài),直到其他線程釋放了信號量,計數(shù)器才會增加,使得線程可以訪問到共享資源。
三、pthread庫的使用
Linux C多線程編程中,pthread庫是最基礎(chǔ)的庫之一,可以實(shí)現(xiàn)各種線程操作,例如創(chuàng)建線程、等待線程、終止線程等。常用的線程函數(shù)包括:pthread_create、pthread_join、pthread_attr_init、pthread_attr_destroy等。
pthread_create函數(shù)可用于創(chuàng)建線程,它的原型如下:
“`c
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
“`
其中,thread參數(shù)是創(chuàng)建線程的ID,attr參數(shù)代表線程的屬性,start_routine函數(shù)是線程的入口函數(shù),arg參數(shù)是傳遞給線程入口函數(shù)的參數(shù)。
pthread_join函數(shù)是用于等待線程結(jié)束的函數(shù),其原型如下:
“`c
int pthread_join(pthread_t thread, void **retval)
“`
其中,thread參數(shù)代表需要等待的線程ID,retval參數(shù)為指向線程的退出狀態(tài)的指針。如果線程已經(jīng)結(jié)束,則pthread_join函數(shù)立即返回。
pthread_attr_init函數(shù)用于初始化線程屬性,pthread_attr_destroy函數(shù)用于釋放線程屬性所占用的資源。
四、互斥鎖
Linux C多線程編程中,互斥鎖是常用的同步機(jī)制之一。Linux提供了兩種類型的互斥鎖:PTHREAD_MUTEX_NORMAL(普通互斥鎖)和PTHREAD_MUTEX_RECURSIVE(遞歸互斥鎖)。
普通互斥鎖只能被解鎖一次,如果一個線程將普通互斥鎖解鎖多次,將導(dǎo)致未定義的行為。
遞歸互斥鎖可以被同一線程多次加鎖,每次加鎖時計數(shù)器加一,解鎖時計數(shù)器減一,只有計數(shù)器為0時,才能被其他線程加鎖。
互斥鎖使用時,首先需要初始化互斥鎖,然后使用pthread_mutex_lock函數(shù)加鎖,再使用pthread_mutex_unlock函數(shù)釋放鎖,如下所示:
“`c
pthread_mutex_t mutex;
void func() {
pthread_mutex_init(&mutex, NULL);
pthread_mutex_lock(&mutex);
// 此處進(jìn)行臨界區(qū)操作
pthread_mutex_unlock(&mutex);
pthread_mutex_destroy(&mutex);
}
“`
五、條件變量
Linux C多線程編程中,條件變量是線程間等待和通知的一種機(jī)制。條件變量的類型為pthread_cond_t,可以通過pthread_cond_init函數(shù)來初始化一個條件變量。
在使用條件變量時,通常需要與互斥鎖一起使用。因為條件變量本身并不提供鎖機(jī)制,可能會出現(xiàn)多個線程同時訪問的問題。當(dāng)一個線程需要等待條件變量時,應(yīng)該先加鎖,然后再等待條件變量的信號通知,如下所示:
“`c
pthread_mutex_t mutex;
pthread_cond_t cond;
void *func(void *arg) {
pthread_mutex_lock(&mutex);
while (condition) {
pthread_cond_wt(&cond, &mutex);
}
pthread_mutex_unlock(&mutex);
}
“`
在其它線程中,可以通過pthread_cond_signal或pthread_cond_broadcast函數(shù)來發(fā)送信號通知,如下所示:
“`c
pthread_mutex_t mutex;
pthread_cond_t cond;
int condition = 0;
void *func(void *arg) {
pthread_mutex_lock(&mutex);
condition = 1;
pthread_cond_signal(&cond); // 發(fā)送信號通知
pthread_mutex_unlock(&mutex);
}
“`
六、信號量
Linux C多線程編程中,信號量是一個最基本的同步機(jī)制,也是多進(jìn)程編程中最常用的同步手段。信號量是一種計數(shù)器,用于控制對一組共享資源的訪問。具體來說,當(dāng)一個線程需要訪問共享資源時,它向信號量請求一個鎖,如果計數(shù)器大于0,那么線程就可以訪問共享資源,同時計數(shù)器減一,如果計數(shù)器為0,那么線程將等待信號量的值發(fā)生變化。
Linux中提供了兩種類型的信號量:二進(jìn)制信號量和計數(shù)信號量。二進(jìn)制信號量只有兩種狀態(tài),一種是0,表示資源不可用,另一種是1,表示資源可用。計數(shù)信號量則是根據(jù)計數(shù)器的值來控制對共享資源的訪問,該值通常初始化為n,表示共享資源有n個。
在使用信號量時,首先需要創(chuàng)建信號量,然后使用sem_wt函數(shù)等待信號量,使用sem_post函數(shù)釋放信號量。
七、
本文主要圍繞Linux C多線程同步技術(shù)展開深入解析,分別從多進(jìn)程同步機(jī)制、多線程同步機(jī)制、pthread庫的使用、互斥鎖、條件變量、信號量等方面進(jìn)行介紹。同步機(jī)制是多線程編程中必不可少的部分,合理地使用同步機(jī)制可以有效避免線程之間的競爭和沖突,從而保證程序的正確性和穩(wěn)定性。
成都網(wǎng)站建設(shè)公司-創(chuàng)新互聯(lián),建站經(jīng)驗豐富以策略為先導(dǎo)10多年以來專注數(shù)字化網(wǎng)站建設(shè),提供企業(yè)網(wǎng)站建設(shè),高端網(wǎng)站設(shè)計,響應(yīng)式網(wǎng)站制作,設(shè)計師量身打造品牌風(fēng)格,熱線:028-86922220linux 多進(jìn)程信號同步問題
朋友你好:希望能幫到你?;ハ鄬W(xué)習(xí)。
線程的更大特點(diǎn)是資源的共享性,但資源共享中的同步問題是多線程編程的難點(diǎn)。清敏linux下提供了多種方式來處理線程裂做同步,最常用的是互斥鎖、條件變量和信號量。
1)互斥鎖(mutex)
通過鎖機(jī)制實(shí)現(xiàn)線程間的同步。同一時刻只允許一個肆正衡線程執(zhí)行一個關(guān)鍵部分的代碼。
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutex_attr_t *mutexattr);
int pthread_mutex_lock(pthread_mutex *mutex);
int pthread_mutex_destroy(pthread_mutex *mutex);
int pthread_mutex_unlock(pthread_mutex *
(1)先初始化鎖init()或靜態(tài)賦值pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIER
attr_t有:
PTHREAD_MUTEX_TIMED_NP:其余線程等待隊列
PTHREAD_MUTEX_RECURSIVE_NP:嵌套鎖,允許線程多次加鎖,不同線程,解鎖后重新競爭
PTHREAD_MUTEX_ERRORCHECK_NP:檢錯,與一同,線程請求已用鎖,返回EDEADLK;
PTHREAD_MUTEX_ADAPTIVE_NP:適應(yīng)鎖,解鎖后重新競爭
(2)加鎖,lock,trylock,lock阻塞等待鎖,trylock立即返回EBUSY
(3)解鎖,unlock需滿足是加鎖狀態(tài),且由加鎖線程解鎖
(4)清除鎖,destroy(此時鎖必需unlock,否則返回EBUSY,//Linux下互斥鎖不占用內(nèi)存資源
示例代碼
#include
#include
#include
#include
#include “iostream”
using namespace std;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int tmp;
void* thread(void *arg)
{
cout
#include
#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;
}
示例程序2:
#include
#include
#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的并發(fā)性
pthread_mutex_lock(&mtx);
while (head == NULL)
{
//這個while要特別說明一下,單個pthread_cond_wait功能很完善,為何
//這里要有一個while (head == NULL)呢?因為pthread_cond_wait里的線
//程可能會被意外喚醒,如果這個時候head != NULL,則不是我們想要的情況。
//這個時候,應(yīng)該讓線程繼續(xù)進(jìn)入pthread_cond_wait
// pthread_cond_wait會先解除之前的pthread_mutex_lock鎖定的mtx,
//然后阻塞在等待對列里休眠,直到再次被喚醒(大多數(shù)情況下是等待的條件成立
//而被喚醒,喚醒后,該進(jìn)程會先鎖定先pthread_mutex_lock(&mtx);,再讀取資源
//用這個流程是比較清楚的/*block–>unlock–>wait() return–>lock*/
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); //臨界區(qū)數(shù)據(jù)操作完畢,釋放互斥鎖
}
pthread_cleanup_pop(0);
return 0;
}
int main(void)
{
pthread_t tid;
int i;
struct node *p;
//子線程會一直等待資源,類似生產(chǎn)者和消費(fèi)者,但是這里的消費(fèi)者可以是多個消費(fèi)者,而
//不僅僅支持普通的單個消費(fèi)者,這個模型雖然簡單,但是很強(qiáng)大
pthread_create(&tid, NULL, thread_func, NULL);
sleep(1);
for (i = 0; i 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”);
//關(guān)于pthread_cancel,有一點(diǎn)額外的說明,它是從外部終止子線程,子線程會在最近的取消點(diǎn),退出
//線程,而在我們的代碼里,最近的取消點(diǎn)肯定就是pthread_cond_wait()了。
pthread_cancel(tid);
pthread_join(tid, NULL);
printf(“All done — exiting/n”);
return 0;
}
3)信號量
如同進(jìn)程一樣,線程也可以通過信號量來實(shí)現(xiàn)通信,雖然是輕量級的。
信號量函數(shù)的名字都以”sem_”打頭。線程使用的基本信號量函數(shù)有四個。
#include
int sem_init (sem_t *sem , int pshared, unsigned int value);
這是對由sem指定的信號量進(jìn)行初始化,設(shè)置好它的共享選項(linux 只支持為0,即表示它是當(dāng)前進(jìn)程的局部信號量),然后給它一個初始值VALUE。
兩個原子操作函數(shù):
int sem_wait(sem_t *sem);
int sem_post(sem_t *sem);
這兩個函數(shù)都要用一個由sem_init調(diào)用初始化的信號量對象的指針做參數(shù)。
sem_post:給信號量的值加1;
sem_wait:給信號量減1;對一個值為0的信號量調(diào)用sem_wait,這個函數(shù)將會等待直到有其它線程使它不再是0為止。
int sem_destroy(sem_t *sem);
這個函數(shù)的作用是再我們用完信號量后都它進(jìn)行清理。歸還自己占有的一切資源。
示例代碼:
#include
#include
#include
#include
#include
#include
#define return_if_fail(p) if((p) == 0){printf (“: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 (“: 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) 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) 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;
}
通 過執(zhí)行結(jié)果后,可以看出,會先執(zhí)行線程二的函數(shù),然后再執(zhí)行線程一的函數(shù)。它們兩就實(shí)現(xiàn)了同步
創(chuàng)新互聯(lián)【028-86922220】值得信賴的成都網(wǎng)站建設(shè)公司。多年持續(xù)為眾多企業(yè)提供成都網(wǎng)站建設(shè),成都品牌建站設(shè)計,成都高端網(wǎng)站制作開發(fā),SEO優(yōu)化排名推廣服務(wù),全網(wǎng)營銷讓企業(yè)網(wǎng)站產(chǎn)生價值。
當(dāng)前題目:深入解析LinuxC多線程同步技術(shù)(linuxc多線程同步)
本文鏈接:http://www.dlmjj.cn/article/dhgoejo.html


咨詢
建站咨詢
