场景
1.原子操作一般用在多线程执行的逻辑里, 比如统计业务个数 ++count, 或者下载文件个数,下载大小, 设置对象状态等. 如果不用原子操作, 那么可能在并发情况下, 原本的事务指令A会被事务指令2抢占而导致出现数据被覆盖.
说明
1.macOS下提供了 <libkern/OSAtomic.h>
来处理 C 方式的原子操作. 如果是object-c方式的原子属性可以使用关键字 atomic
.
2.C++11(vs2012以上)也提供了方便使用可移植的 Atomic Library
,
例子
#include <CoreFoundation/CoreFoundation.h>
#import <Foundation/Foundation.h>
#include <time.h>
#include <vector>
#include <atomic>
#include <algorithm>
#include <pthread.h>
#include <libkern/OSAtomic.h>
void TestAtomic(){
NSLog(@"TestAtomic");
volatile int64_t foo = 1;
NSLog(@"foo is %lld",foo);
// ++
OSAtomicIncrement64(&foo);
NSLog(@"++ OSAtomicIncrement64: %lld",foo);
// --
OSAtomicDecrement64(&foo);
NSLog(@"-- OSAtomicDecrement64: %lld",foo);
// =
OSAtomicCompareAndSwap64(foo, 64, &foo);
NSLog(@"= OSAtomicCompareAndSwap64: %lld",foo);
// +=
OSAtomicAdd64(36, &foo);
NSLog(@"+= OSAtomicAdd64: %lld",foo);
// -=
OSAtomicAdd64(-36, &foo);
NSLog(@"-= OSAtomicAdd64: %lld",foo);
}
void TestCppAtomicLibrary(){
NSLog(@"TestCppAtomicLibrary");
std::atomic<int64_t> foo(1);
NSLog(@"foo is %lld",foo.load());
// ++
++foo;
NSLog(@"++ OSAtomicIncrement64: %lld",foo.load());
// --
--foo;
NSLog(@"-- OSAtomicDecrement64: %lld",foo.load());
// =
foo = 64;
NSLog(@"= OSAtomicCompareAndSwap64: %lld",foo.load());
// +=
foo+=36;
NSLog(@"+= OSAtomicAdd64: %lld",foo.load());
// -=
foo-=36;
NSLog(@"-= OSAtomicAdd64: %lld",foo.load());
}
#define THREAD_COUNT 100
#define FOR_NUMBER 10000
static volatile int32_t count = 0;
static pthread_mutex_t mutex;
static pthread_cond_t cond;
static volatile int64_t foo = 1;
static std::atomic<int64_t> foo1(1);
void* RunCAtomic(void*){
for(int i = 0; i< FOR_NUMBER;++i){
OSAtomicIncrement64(&foo); // fail if ++foo
OSAtomicAdd64(36, &foo);
}
for(int i = 0; i< FOR_NUMBER;++i){
OSAtomicDecrement64(&foo);
OSAtomicAdd64(-36, &foo);
}
OSAtomicIncrement32(&count);
if(OSAtomicCompareAndSwap32(THREAD_COUNT, 0, &count)){
assert(count == 0);
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
void* RunCppAtomic(void*){
for(int i = 0; i< FOR_NUMBER;++i){
++foo1;
foo1+=36;
}
for(int i = 0; i< FOR_NUMBER;++i){
--foo1;
foo1-=36;
}
OSAtomicIncrement32(&count);
if(OSAtomicCompareAndSwap32(THREAD_COUNT, 0, &count)){
assert(count == 0);
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main(int argc, const char * argv[])
{
NSAutoreleasePool* pool = [NSAutoreleasePool new];
TestAtomic();
TestCppAtomicLibrary();
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_attr_t att;
pthread_attr_init(&att);
pthread_attr_setdetachstate(&att, PTHREAD_CREATE_JOINABLE);
NSLog(@"Begin CAtomic");
for(int i = 0; i < THREAD_COUNT;++i){
pthread_t t;
pthread_create(&t,&att,RunCAtomic,NULL);
}
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
assert(foo == 1);
NSLog(@"End CAtomic");
NSLog(@"Begin CppAtomic");
for(int i = 0; i < THREAD_COUNT;++i){
pthread_t t;
pthread_create(&t,&att,RunCppAtomic,NULL);
}
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
assert(foo1.load() == 1);
NSLog(@"End CAtomic");
[pool drain];
return 0;
}
输出:
2017-07-11 10:26:18.162 TestObjc[744:303] TestAtomic
2017-07-11 10:26:18.165 TestObjc[744:303] foo is 1
2017-07-11 10:26:18.165 TestObjc[744:303] ++ OSAtomicIncrement64: 2
2017-07-11 10:26:18.166 TestObjc[744:303] -- OSAtomicDecrement64: 1
2017-07-11 10:26:18.166 TestObjc[744:303] = OSAtomicCompareAndSwap64: 64
2017-07-11 10:26:18.167 TestObjc[744:303] += OSAtomicAdd64: 100
2017-07-11 10:26:18.167 TestObjc[744:303] -= OSAtomicAdd64: 64
2017-07-11 10:26:18.168 TestObjc[744:303] TestCppAtomicLibrary
2017-07-11 10:26:18.168 TestObjc[744:303] foo is 1
2017-07-11 10:26:18.169 TestObjc[744:303] ++ OSAtomicIncrement64: 2
2017-07-11 10:26:18.169 TestObjc[744:303] -- OSAtomicDecrement64: 1
2017-07-11 10:26:18.170 TestObjc[744:303] = OSAtomicCompareAndSwap64: 64
2017-07-11 10:26:18.170 TestObjc[744:303] += OSAtomicAdd64: 100
2017-07-11 10:26:18.171 TestObjc[744:303] -= OSAtomicAdd64: 64
2017-07-11 10:26:18.171 TestObjc[744:303] Begin CAtomic
2017-07-11 10:26:18.259 TestObjc[744:303] End CAtomic
2017-07-11 10:26:18.260 TestObjc[744:303] Begin CppAtomic
2017-07-11 10:26:18.360 TestObjc[744:303] End CAtomic