C/C++ 线程三种并发方式比较(传统互斥量加锁方式, no lock不加锁的方式, 原子函数方式)
執(zhí)行速度結(jié)果:
- 傳統(tǒng)互斥量加鎖方式 <?no lock不加鎖的方式 <?原子函數(shù)方式
正文如下:
最近編碼需要實(shí)現(xiàn)多線程環(huán)境下的計(jì)數(shù)器操作,統(tǒng)計(jì)相關(guān)事件的次數(shù)。下面是一些學(xué)習(xí)心得和體會(huì)。不敢妄稱原創(chuàng),基本是學(xué)習(xí)筆記。遇到相關(guān)的引用,我會(huì)致謝。
??? 當(dāng)然我們知道,count++這種操作不是原子的。一個(gè)自加操作,本質(zhì)是分成三步的:
?????1 從緩存取到寄存器
???? 2 在寄存器加1
???? 3 存入緩存。
mov eax,dword ptr [a]
add eax,1
mov dword ptr [a],eax
由于時(shí)序的因素,多個(gè)線程操作同一個(gè)全局變量,會(huì)出現(xiàn)問(wèn)題。這也是并發(fā)編程的難點(diǎn)。在目前多核條件下,這種困境會(huì)越來(lái)越彰顯出來(lái)。
最簡(jiǎn)單的處理辦法就是加鎖保護(hù),這也是我最初的解決方案。看下面的代碼:
后來(lái)在網(wǎng)上查找資料,找到了__sync_fetch_and_add系列的命令
?????__sync_fetch_and_add系列一共有十二個(gè)函數(shù),有加/減/與/或/異或/等函數(shù)的原子性操作函數(shù),
__snyc_fetch_and_add : 先f(wàn)etch然后自加,返回的是自加以前的值 __snyc_add_and_fetch : 先自加然后返回,返回的是自加以后的值 (參照 ++i 和 i++)__snyc_fetch_and_add的一個(gè)簡(jiǎn)單使用 int count = 4; __sync_fetch_and_add(&count, 1); // __sync_fetch_and_add(&count, 1) == 4 cout<<count<<endl; //--->count=5?對(duì)于多線程對(duì)全局變量進(jìn)行自加,我們就再也不用理線程鎖了。
下面這行代碼,和上面被pthread_mutex保護(hù)的那行代碼作用是一樣的,而且也是線程安全的。
__sync_fetch_and_add( &global_int, 1 );下面是這群函數(shù)的全家福,大家看名字就知道是這些函數(shù)是干啥的了。
//在用gcc編譯的時(shí)候要加上選項(xiàng) -march=i686
type __sync_fetch_and_add (type *ptr, type value, ...);
type __sync_fetch_and_sub (type *ptr, type value, ...);
type __sync_fetch_and_or (type *ptr, type value, ...);
type __sync_fetch_and_and (type *ptr, type value, ...);
type __sync_fetch_and_xor (type *ptr, type value, ...);
type __sync_fetch_and_nand (type *ptr, type value, ...);
type __sync_add_and_fetch (type *ptr, type value, ...);
type __sync_sub_and_fetch (type *ptr, type value, ...);
type __sync_or_and_fetch (type *ptr, type value, ...);
type __sync_and_and_fetch (type *ptr, type value, ...);
type __sync_xor_and_fetch (type *ptr, type value, ...);
type __sync_nand_and_fetch (type *ptr, type value, ...);
__sync_fetch_and_add,速度是線程鎖的6~7倍
type可以是1,2,3或者8字節(jié)長(zhǎng)度的int類(lèi)型,即
int8_t ? ?
uint8_t
int16_t
uint16_t
int32_t
uint32_t
int64_t
uint64_t
后面的可擴(kuò)展參數(shù)(...)用來(lái)指出哪些變量需要memory barrier,因?yàn)槟壳癵cc實(shí)現(xiàn)的是full barrier(類(lèi)似于linux kernel 中的mb(),表示這個(gè)操作之前的所有內(nèi)存操作不會(huì)被重排序到這個(gè)操作之后),所以可以略掉這個(gè)參數(shù)。
恩.再找個(gè)帖子學(xué)習(xí)學(xué)習(xí).http://blog.csdn.net/hzhsan/article/details/25124901
有一個(gè)概念叫過(guò)無(wú)鎖化編程,?知道linux支持的哪些操作是具有原子特性的是理解和設(shè)計(jì)無(wú)鎖化編程算法的基礎(chǔ)
除了上面提到的12個(gè)外 還有4個(gè)可以實(shí)現(xiàn)互斥鎖的功能
//以下兩個(gè)函數(shù)提供原子的比較和交換, 如果*ptr = oldValue, 就將newValue寫(xiě)入*ptr //第一個(gè)函數(shù)在相等并寫(xiě)入的情況下返回true //第二個(gè)函數(shù)返回操作之前的值bool __sync_bool_compare_and_swap(type* ptr, type oldValue, type newValue, ....);type __sync_val_compare_and_swap(type* ptr, type oldValue, type newValue, ....);//將*ptr設(shè)為value并返回*ptr操作之前的值 type __sync_lock_test_and_set(type *ptr, type value, ....);//置*ptr為0 void __sync_lock_release(type* ptr, ....); __sync_synchronize(...)//作用 : 發(fā)出一個(gè)full barrier /*關(guān)于memory barrier,cpu會(huì)對(duì)我們的指令進(jìn)行排序,一般說(shuō)來(lái)會(huì)提高程序的效率,但有時(shí)候可能造成我們不希望得到的結(jié)果,舉一個(gè)例子,比如我們有一個(gè)硬件設(shè)備,它有4個(gè)寄存器,當(dāng)你發(fā)出一個(gè)操作指令的時(shí)候,一個(gè)寄存器存的是你的操作指令(比如READ),兩個(gè)寄存器存的是參數(shù)(比如是地址和size),最后一個(gè)寄存器是控制寄存器,在所有的參數(shù)都設(shè)置好之后向其發(fā)出指令,設(shè)備開(kāi)始讀取參數(shù),執(zhí)行命令,程序可能如下:*/ write1(dev.register_size, size); write1(dev.register_addr, addr); write1(dev.register_cmd, Read); write1(dev.register_control, GO); /*如果最后一條write1被換到了前幾條語(yǔ)句之前,那么肯定不是我們所期望的,這時(shí)候我們可以在最后一條語(yǔ)句之前加入一個(gè)memory barrier,強(qiáng)制cpu執(zhí)行完前面的寫(xiě)入以后再執(zhí)行最后一條:*/ write1(dev.register_size, size); write1(dev.register_addr, addr); write1(dev.register_cmd, Read); __sync_synchronize(); write1(dev.register_control, GO);//memory barrier有幾種類(lèi)型: //acquire barrier : 不允許將barrier之后的內(nèi)存讀取指令移到barrier之前(linux kernel中的wmb()) //release barrier : 不允許將barrier之前的內(nèi)存讀取指令移到barrier之后 (linux kernel中的rmb()) //full barrier : 以上兩種barrier的合集(linux kernel中的mb())//好吧,說(shuō)實(shí)話這個(gè)函數(shù)的說(shuō)明基本沒(méi)看懂最后從網(wǎng)上找一個(gè)代碼寫(xiě)一寫(xiě):http://blog.csdn.net/hzhsan/article/details/25837189
測(cè)試場(chǎng)景:假設(shè)有一個(gè)應(yīng)用:現(xiàn)在有一個(gè)全局變量,用來(lái)計(jì)數(shù),再創(chuàng)建10個(gè)線程并發(fā)執(zhí)行,每個(gè)線程中循環(huán)對(duì)這個(gè)全局變量進(jìn)行++操作(i++),循環(huán)加2000000次。
所以很容易知道,這必然會(huì)涉及到并發(fā)互斥操作。下面通過(guò)三種方式[傳統(tǒng)互斥量加鎖方式, no lock不加鎖的方式, 原子函數(shù)方式]來(lái)實(shí)現(xiàn)這種并發(fā)操作。并對(duì)比出其在效率上的不同之處。
這里先貼上代碼,共5個(gè)文件:2個(gè)用于做時(shí)間統(tǒng)計(jì)的文件:timer.h? timer.cpp。這兩個(gè)文件是臨時(shí)封裝的,只用來(lái)計(jì)時(shí),可以不必細(xì)看。
//timer.h 用于計(jì)時(shí)#ifndef TIMER_H_ #define TIMER_H_#include <sys/time.h>class Timer {public:Timer();Timer(const Timer& t) = delete;~Timer();void start();void stop();void reset();double costTime();private: struct timeval t1;struct timeval t2;bool b1, b2; }; #endif //timer.cpp #include "timer.h" #include <iostream>using namespace std;Timer::Timer():b1(false), b2(false) { } Timer::~Timer() { } void Timer::start() {gettimeofday(&t1, NULL);b1 = true;b2 = false; } void Timer::stop() {gettimeofday(&t2, NULL);b2 = true; } void Timer::reset() {b1 = false;b2 = false; } double Timer::costTime() {if (!b1){cout<<"error, do not call function start()"<<endl;cout<<"the right sequence : start() ..... stop() costTime()"<<endl;return 0;}if (!b2){cout<<"error, do not call function stop()"<<endl;cout<<"the right sequence : start() ..... stop() costTime()"<<endl;return 0;}size_t sec = t2.tv_sec - t1.tv_sec; double usec = t2.tv_usec - t1.tv_usec;if (sec < 0) {cout<<"error, call stop() before start()"<<endl;cout<<"the right sequence : start() ..... stop() costTime()"<<endl;return 0;}if (usec < 0){usec += 1000000;--sec;if (sec < 0) {cout<<"error, call stop() before start()"<<endl;cout<<"the right sequence : start() ..... stop() costTime()"<<endl;return 0;}}return sec + usec * 1.0 / 1000000; } //thread_function.h -->多線程要調(diào)用的函數(shù) #ifndef THREAD_FUNCTION_H_ #define THREAD_FUNCTION_H_ void* thread_lock_execFunc(void* arg); void* thread_nolock_execFunc(void* arg); void* thread_atom_execFunc(void* arg); #endif //thread_function.cpp #include "thread_function.h" #include "lock.h" #include <pthread.h> #include <unistd.h>extern volatile int count; struct LOCK;void* thread_lock_execFunc(void* arg) {for (int i = 0; i < 2000000; ++i){pthread_mutex_lock(reinterpret_cast<pthread_mutex_t*>(arg));++count;pthread_mutex_unlock(reinterpret_cast<pthread_mutex_t*>(arg));}return NULL; }void* thread_nolock_execFunc(void* arg) {LOCK* pLock = reinterpret_cast<LOCK*>(arg);for (int i = 0; i < 2000000; ++i){while(!(__sync_bool_compare_and_swap(&(pLock->mutex), pLock->use, 1))){usleep(100000);}++count;__sync_bool_compare_and_swap(&(pLock->mutex), pLock->unUse, 0);}return NULL; }void* thread_atom_execFunc(void* arg) {for (int i = 0; i < 2000000; ++i){__sync_fetch_and_add(&count, 1);}return NULL; } //lock.h --->給mainnolock.cpp使用的類(lèi) #ifndef LOCK_H_ #define LOCK_H_ struct LOCK {int mutex;int use;int unUse;LOCK() : mutex(0), use(0), unUse(1){} }; #endif //mainlock.cpp 使用mutex加鎖方式的多線程 #include <iostream> #include <pthread.h> #include <iomanip>#include "timer.h" #include "thread_function.h"using namespace std;pthread_mutex_t mutex_lock; volatile int count = 0;int main( int argc, char** argv) {pthread_mutex_init(&mutex_lock, NULL);Timer timer;timer.start();/*test thread begin*/pthread_t thread_ids[10];for (int i = 0; i < sizeof(thread_ids)/sizeof(pthread_t); ++i){pthread_create(&thread_ids[i], NULL, thread_lock_execFunc, &mutex_lock);}for (int i = 0; i < sizeof(thread_ids)/sizeof(pthread_t); ++i){pthread_join(thread_ids[i], NULL);}/*test thread end*/timer.stop();cout<<setiosflags(ios::fixed)<<setprecision(4)<<"lock cost["<<timer.costTime()<<"]second"<<endl;return 0; } //main_nolock.cpp 使用__sync_compare_and_swap的多線程 #include <iostream> #include <pthread.h> #include <unistd.h> #include <iomanip> #include "timer.h" #include "thread_function.h" #include "lock.h"using namespace std;volatile int count = 0;int main(int argc, char** argv) {LOCK lock;Timer timer;timer.start();/*test thread begin*/pthread_t thread_ids[10];for (int i = 0; i < sizeof(thread_ids) / sizeof(pthread_t); ++i){pthread_create(&thread_ids[i], NULL, thread_nolock_execFunc, &lock);}for (int i = 0; i < sizeof(thread_ids) / sizeof(pthread_t); ++i){pthread_join(thread_ids[i], NULL);}/*test thread end*/timer.stop();cout<<setiosflags(ios::fixed)<<setprecision(4)<<"nolock cost["<<timer.costTime()<<"]\n"; return 0; } //main_atomic.cpp 使用__sync_fetch_and_add的多線程 #include<iostream> #include<pthread.h> #include<unistd.h> #include<iomanip> #include "timer.h" #include "thread_function.h"using namespace std;volatile int count = 0;int main(int argc, char** argv) {Timer timer;timer.start();/*pthread begin*/pthread_t thread_ids[10];for (int i = 0; i < sizeof(thread_ids)/sizeof(pthread_t); ++i){pthread_create(&thread_ids[i], NULL, thread_atom_execFunc, NULL);}for (int i = 0; i < sizeof(thread_ids)/sizeof(pthread_t); ++i){pthread_join(thread_ids[i], NULL);}/*pthread end*/timer.stop();cout<<setiosflags(ios::fixed)<<setprecision(4)<<"atomic cost["<<timer.costTime()<<"]\n";return 0; } //makefileCC = g++ CFLAGS = -g -lpthread -std=c++11OBJS_LOCK = main_lock.o timer.o thread_function.o OBJS_UNLOCK = main_nolock.o timer.o thread_function.o OBJS_ATOMICLOCK = main_atomic.o timer.o thread_function.oINC = timer.h thread_function.h lock.hlock : $(OBJS_LOCK) $(INC) $(CC) -o mainlock $(OBJS_LOCK) $(CFLAGS)rm *.onolock : $(OBJS_UNLOCK) $(INC)$(CC) -o mainnolock $(OBJS_UNLOCK) $(CFLAGS)rm *.oatomiclock : $(OBJS_ATOMICLOCK) $(INC)$(CC) -o mainatomic $(OBJS_ATOMICLOCK) $(CFLAGS)main_lock.o : main_lock.cpp $(CC) -c main_lock.cpp $(CFLAGS)main_nolock.o : main_nolock.cpp $(CC) -c main_nolock.cpp $(CFLAGS)main_atomic.o : main_atomic.cpp$(CC) -c main_atomic.cpp $(CFLAGS)timer.o : timer.cpp $(CC) -c timer.cpp $(CFLAGS)thread_function.o : thread_function.cpp$(CC) -c thread_function.cpp $(CFLAGS)clean:rm *.o執(zhí)行makefile
make lock
make nolock
make atomiclock
然后生成3個(gè)可執(zhí)行文件
運(yùn)行這3個(gè)可執(zhí)行文件:
另外:針對(duì)main_nolock.cpp而言,作者提到了一個(gè)現(xiàn)象
在thread_function.cpp中, 隨著一下代碼的改變,運(yùn)行時(shí)間會(huì)有變化
while (!(__sync_bool_compare_and_swap (&mutex,lock, 1) ));?
while (!(__sync_bool_compare_and_swap (&mutex,lock, 1) )) usleep(1);
while (!(__sync_bool_compare_and_swap (&mutex,lock, 1) ))usleep(10);
while (!(__sync_bool_compare_and_swap (&mutex,lock, 1) ))usleep(100);
while (!(__sync_bool_compare_and_swap (&mutex,lock, 1) ))usleep(1000);
while (!(__sync_bool_compare_and_swap (&mutex,lock, 1) ))usleep(10000);
while (!(__sync_bool_compare_and_swap (&mutex,lock, 1) ))usleep(100000);
執(zhí)行時(shí)間的關(guān)系是 ?: ? ?T(;)<T(1)<T(10)<T(100)<T(1000)<T(10000)>T(100000)
?通過(guò)編程測(cè)試及測(cè)試得出結(jié)論:
1、如果是想用全局變量來(lái)做統(tǒng)計(jì)操作。而又不得不考慮多線程間的互斥訪問(wèn)的話,最好使用編譯器支持的原子操作函數(shù)。再滿足互斥訪問(wèn)的前提下,編程最簡(jiǎn)單,效率最高。
2、lock-free,無(wú)鎖編程方式確實(shí)能夠比傳統(tǒng)加鎖方式效率高。所以在高并發(fā)程序中采用無(wú)鎖編程的方式可以進(jìn)一步提高程序效率。但是得對(duì)無(wú)鎖方式有足夠熟悉的了解,不然效率反而會(huì)更低而且容易出錯(cuò)。(比如在某些情況下main_nolock比main_lock的效率還要低)
在學(xué)習(xí)一個(gè)無(wú)鎖化編程的分析帖子?http://blog.csdn.net/hzhsan/article/details/25141421
Lock-free 算法通常比基于鎖的算法要好:
- 從其定義來(lái)看,它們是 wait-free 的,可以確保線程永遠(yuǎn)不會(huì)阻塞。
- 狀態(tài)轉(zhuǎn)變是原子性的,以至于在任何點(diǎn)失敗都不會(huì)惡化數(shù)據(jù)結(jié)構(gòu)。
- 因?yàn)榫€程永遠(yuǎn)不會(huì)阻塞,所以當(dāng)同步的細(xì)粒度是單一原子寫(xiě)或比較交換時(shí),它們通常可以帶來(lái)更高的吞吐量。
- 在某些情況下,lock-free 算法會(huì)有更少的同步寫(xiě)操作(比如 Interlocked 操作),因此純粹從性能來(lái)看,它可能更便宜。
但是 lock-freedom 并不是萬(wàn)能藥。下面是一些很明顯的不利因素:
- 樂(lè)觀的并發(fā)使用會(huì)對(duì) hot data structures 導(dǎo)致 livelock。
- 代碼需要大量困難的測(cè)試。通常其正確性取決于對(duì)目標(biāo)機(jī)器內(nèi)存模型的正確解釋。
- 基于眾多原因,lock-free 代碼很難編寫(xiě)和維護(hù)。
無(wú)鎖編程主要是使用原子操作替代鎖來(lái)實(shí)現(xiàn)對(duì)共享資源的訪問(wèn)保護(hù),舉個(gè)例子,要對(duì)某個(gè)整數(shù)變量進(jìn)行加1操作的話,用鎖保護(hù)操作的代碼如下:
int a = 0;
Lock();
a+= 1;
Unlock();
如果對(duì)上述代碼反編譯可以發(fā)現(xiàn) a+=1;被翻譯成了以下三條匯編指令:
mov eax,dword ptr [a]
add eax,1
mov dword ptr [a],eax
如果在單核系統(tǒng)中,由于在上述三條指令的任何一條執(zhí)行完后都可能發(fā)生任務(wù)切換,比如執(zhí)行完第1條指令后就發(fā)生了任務(wù)切換,這時(shí)如果有其他任務(wù)來(lái)對(duì)a進(jìn)行操作的話,當(dāng)任務(wù)切換回來(lái)后,將繼續(xù)對(duì)a進(jìn)行操作,很可能出現(xiàn)不可預(yù)測(cè)的結(jié)果,因此上述三條指令必須使用鎖來(lái)保護(hù),以使這段時(shí)間內(nèi)其他任務(wù)無(wú)法對(duì)a進(jìn)行操作。
需要注意的是,在多核系統(tǒng)中,因?yàn)槎鄠€(gè)CPU核在物理上是并行的,可能發(fā)生同時(shí)寫(xiě)的現(xiàn)象;所以必須保證一個(gè)CPU核在對(duì)共享內(nèi)存進(jìn)行寫(xiě)操作時(shí),其他CPU核不能寫(xiě)這塊內(nèi)存。因此在多核系統(tǒng)中和單核有區(qū)別,即使只有一條指令,也需要要加鎖保護(hù)。
如果使用原子操作來(lái)實(shí)現(xiàn)上述加1操作的話,例如使用VC里的InterlockedIncrement來(lái)操作的話,那么對(duì)a的加1操作需要以下語(yǔ)句
InterlockedIncrement (&a);
這條語(yǔ)句最終的實(shí)際加1操作會(huì)被翻譯成以下一條帶lock前綴的匯編指令:
lock xadd dword ptr [ecx],eax
使用原子操作時(shí),在進(jìn)行實(shí)際的寫(xiě)操作時(shí),使用了lock指令,這樣就可以阻止其他任務(wù)寫(xiě)這塊內(nèi)存,避免出現(xiàn)數(shù)據(jù)競(jìng)爭(zhēng)現(xiàn)象。原子操作速度比鎖快,一般要快一倍以上。
使用lock前綴的指令實(shí)際上在系統(tǒng)中是使用了內(nèi)存柵障(memory barrier),當(dāng)原子操作在進(jìn)行時(shí),其他任務(wù)都不能對(duì)內(nèi)存操作,會(huì)影響其他任務(wù)的執(zhí)行。因此這種原子操作實(shí)際上屬于一種激烈競(jìng)爭(zhēng)的鎖,不過(guò)由于它的操作時(shí)間很快,因此可以看成是一種極細(xì)粒度鎖。
在無(wú)鎖(Lock-free)編程環(huán)境中,主要使用的原子操作為CAS(Compare and Swap)操作,在VC里對(duì)應(yīng)的操作為InterlockedCompareExchange或者InterlockedCompareExchangeAcquire;如果是64位的操作,需要使用InterlockedCompareExchange64或者InterlockedCompareExchangeAcquire64。使用這種原子操作替代鎖的最大的一個(gè)好處是它是非阻塞的。
| ? | 比較項(xiàng)目 | 無(wú)鎖編程 | 分布式編程 |
| 1 | 加速比性能 | 取決于競(jìng)爭(zhēng)方式,除非也采用分布式競(jìng)爭(zhēng),否則不如分布式鎖競(jìng)爭(zhēng)的性能 | 加速比和CPU核數(shù)成正比關(guān)系,接近于單核多任務(wù)時(shí)的性能 |
| 2 | 實(shí)現(xiàn)的功能 | 有限 | 不受限制 |
| 3 | 程序員掌握難易程度 | 難度太高,過(guò)于復(fù)雜,普通程序員無(wú)法掌握,目前世界上只有少數(shù)幾個(gè)人掌握。 | 和單核時(shí)代的數(shù)據(jù)結(jié)構(gòu)算法難度差不多,普通程序員可以掌握 |
| 4 | 現(xiàn)有軟件的移植 | 使用無(wú)鎖算法后,以往的算法需要廢棄掉,無(wú)法復(fù)用 | 可以繼承已有的算法,在已有程序基礎(chǔ)上重構(gòu)即可。 |
從上表的四個(gè)方面的綜合比較可以看出,無(wú)鎖編程的實(shí)用價(jià)值是遠(yuǎn)遠(yuǎn)不如分布式編程的,因此分布式編程比無(wú)鎖編程更適合多核CPU系統(tǒng)。
可在分布計(jì)算機(jī)系統(tǒng)的幾臺(tái)計(jì)算機(jī)上同時(shí)協(xié)調(diào)執(zhí)行的程序設(shè)計(jì)方法,分布式程序設(shè)計(jì)的主要特征是分布和通信。采用分布式程序設(shè)計(jì)方法設(shè)計(jì)程序時(shí),一個(gè)程序由若干個(gè)可獨(dú)立執(zhí)行的程序模塊組成。這些程序模塊分布于一個(gè)分布式計(jì)算機(jī)系統(tǒng)的幾臺(tái)計(jì)算機(jī)上同時(shí)執(zhí)行。分布在各臺(tái)計(jì)算機(jī)上的程序模塊是相互關(guān)聯(lián)的,它們?cè)趫?zhí)行中需要交換數(shù)據(jù),即通信。只有通過(guò)通信,各程序模塊才能協(xié)調(diào)地完成一個(gè)共同的計(jì)算任務(wù)。采用分布式程序設(shè)計(jì)方法解決計(jì)算問(wèn)題時(shí),必須提供用以進(jìn)行分布式程序設(shè)計(jì)的語(yǔ)言和設(shè)計(jì)相應(yīng)的分布式算法。分布式程序設(shè)計(jì)語(yǔ)言與常用的各種程序設(shè)計(jì)語(yǔ)言的主要區(qū)別,在于它具有程序分布和通信的功能。因此,分布式程序設(shè)計(jì)語(yǔ)言,往往可以由一種程序設(shè)計(jì)語(yǔ)言增加分布和通信的功能而構(gòu)成。分布式算法和適用于多處理器系統(tǒng)的并行算法,都具有并行執(zhí)行的特點(diǎn),但它們是有區(qū)別的。設(shè)計(jì)分布式算法時(shí),必須保證實(shí)現(xiàn)算法的各程序模塊間不會(huì)有公共變量,它們只能通過(guò)通信來(lái)交換數(shù)據(jù)。此外,設(shè)計(jì)分布式算法時(shí),往往需要考慮堅(jiān)定性,即當(dāng)系統(tǒng)中幾臺(tái)計(jì)算機(jī)失效時(shí),算法仍是有效的。
總結(jié)
以上是生活随笔為你收集整理的C/C++ 线程三种并发方式比较(传统互斥量加锁方式, no lock不加锁的方式, 原子函数方式)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: C/C++ 去掉字符串首位的空格字符
- 下一篇: C/C++取绝对值