更新時(shí)間:2021-10-09 10:45:11 來源:動(dòng)力節(jié)點(diǎn) 瀏覽1319次
線程是一個(gè)執(zhí)行單元,由其程序計(jì)數(shù)器、堆棧和一組寄存器組成。人們總是混淆線程和進(jìn)程,區(qū)別很簡(jiǎn)單,進(jìn)程提供執(zhí)行程序所需的資源,而線程是進(jìn)程內(nèi)可以調(diào)度執(zhí)行的實(shí)體。線程比進(jìn)程有很多優(yōu)點(diǎn),主要的優(yōu)點(diǎn)是,線程通過并行改進(jìn)應(yīng)用程序。我們將利用這個(gè)并行概念來編寫一個(gè)簡(jiǎn)單的 C 并理解為什么我們需要線程同步。
讓我們編寫一個(gè)具有單線程的簡(jiǎn)單 C 程序。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
volatile long int a = 0;
int main()
{
int i;
a = 0;
for(i = 0; i < 100000; i++)
{
a = a + i;
}
printf("%ld\n",a);
return 0;
}
上面的代碼很簡(jiǎn)單,它是單線程的,不用擔(dān)心并行性。當(dāng)我們執(zhí)行并運(yùn)行上面的代碼時(shí),我們每次都會(huì)得到4999950000。該代碼具有三個(gè)主要的機(jī)器代碼指令。
LDR R0, a
ADD R0, R0, R1
STR R0, a
現(xiàn)在讓我們稍微修改一下多線程的代碼,看看它的行為。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
volatile long int a = 0;
pthread_mutex_t aLock;
void threadFunc()
{
int i;
for (i = 1; i < 200000 ; i++)
{
a = a + 1;
}
}
void threadFunc2()
{
int i;
for(i = 200000; i <= 500000; i++)
{
a = a + i;
}
}
int main()
{
pthread_t th_one, th_two;
int i;
a = 0;
pthread_create(&th_one, NULL, (void*)&threadFunc, NULL); // Create a new thread for threadFunc
pthread_create(&th_two, NULL, (void*)&threadFunc2, NULL); // Create a new thread for threadFunc2
pthread_join(th_one, NULL); // waiting to join thread "th_one" without status
pthread_join(th_two, NULL); // waiting to join thread "th_two" without status
printf("%ld\n",a);
return 0;
}
我們創(chuàng)建了兩個(gè)新線程threadFunc和threadFunc2。讓我們用命令編譯上面的代碼
$ gcc -pthread m_thread.c -o m_thread
當(dāng)我們多次運(yùn)行二進(jìn)制 m_thread 時(shí),我們會(huì)看到類似這樣的內(nèi)容
令我們驚訝的是,輸出是不確定的。那么,造成這種奇怪現(xiàn)象的原因可能是什么?為什么我的電腦會(huì)這樣?答案是,我們沒有處理線程同步。讓我們了解為什么會(huì)發(fā)生這種情況。
在 SC1 中,'a' 被加載到 th1 的本地內(nèi)存中,然后它執(zhí)行操作并存儲(chǔ)回主內(nèi)存。類似地,在 SC2 中,'a' 被加載到 th2 的本地內(nèi)存中,并在操作后存儲(chǔ)回主內(nèi)存。現(xiàn)在,在 SC3 'a' 由 th1 和 th2 獲取,因?yàn)闆]有線程同步,因此我們可以看到 th1 存儲(chǔ)的值丟失了,操作后基本上由 th2 更新。這是我為我們的理解添加的一個(gè)結(jié)果。然而,每次我們朗姆酒二進(jìn)制可執(zhí)行文件時(shí),后臺(tái)都會(huì)發(fā)生許多這樣的后果,導(dǎo)致不同的輸出。
現(xiàn)在,我們?nèi)绾螌?shí)現(xiàn)進(jìn)程同步?一種方法是使用互斥鎖。請(qǐng)參閱下面的修改示例。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
volatile long int a = 0;
pthread_mutex_t aLock;
void threadFunc(void* arg)
{
int i;
for (i = 1; i < 200000 ; i++)
{
pthread_mutex_lock(&aLock); // Lock a mutex for a
a = a + 1;
pthread_mutex_unlock(&aLock); // Unlock a mutex for a
}
}
void threadFunc2(void *arg)
{
int i;
for(i = 200000; i <= 500000; i++)
{
pthread_mutex_lock(&aLock); // Lock a Mutex for a
a = a + i;
pthread_mutex_unlock(&aLock); // Unlock a mutex for a
}
}
int main()
{
pthread_t th_one, th_two;
int i;
a = 0;
pthread_create(&th_one, NULL, (void*)&threadFunc, NULL); // Create a new thread for threadFunc
pthread_create(&th_two, NULL, (void*)&threadFunc2, NULL); // Create a new thread for threadFunc2
pthread_join(th_one, NULL); // waiting to join thread "one" without status
pthread_join(th_two, NULL); // waiting to join thread "two" without status
printf("%ld\n",a);
return 0;
當(dāng)我們執(zhí)行上述二進(jìn)制文件時(shí),我們每次運(yùn)行都會(huì)得到相同的輸出。
在這種方法中,在代碼的入口部分,在臨界區(qū)內(nèi)修改和使用的關(guān)鍵資源上獲取一個(gè) LOCK,并在退出部分釋放 LOCK。由于資源在進(jìn)程執(zhí)行其臨界區(qū)時(shí)被鎖定,因此其他進(jìn)程無(wú)法訪問它。
以上就是多線程同步的例子,大家若想了解更多相關(guān)信息,可以關(guān)注一下動(dòng)力節(jié)點(diǎn)的Java多線程編程教程,里面有更詳細(xì)的知識(shí)可以學(xué)習(xí),希望對(duì)大家能夠有所幫助。
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
有基礎(chǔ) 直達(dá)就業(yè)
業(yè)余時(shí)間 高薪轉(zhuǎn)行
工作1~3年,加薪神器
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問老師會(huì)電話與您溝通安排學(xué)習(xí)