YYCache源碼解讀

YYCache是一個(gè)線程安全的高性能鍵值緩存組件,代碼質(zhì)量很高,他的作者是國(guó)內(nèi)開發(fā)者ibireme開發(fā)并且開源的. 下面就來(lái)簡(jiǎn)單剖析一下他的源碼.如有哪里錯(cuò)誤希望拍磚!多多交流多多進(jìn)步!謝謝!!!

基本使用方法


//要緩存的對(duì)象
NSString*name =@"JJCoderMa";
//需要緩存的對(duì)象在緩存里對(duì)應(yīng)的鍵
NSString *key =@"username";
//創(chuàng)建一個(gè)YYCache實(shí)例:userInfoCache
YYCache *userInfoCache = [YYCache cacheWithName:@"userInfocache"];
//存入鍵值對(duì)
[userInfoCache setObject:userName forKey:key withBlock:^{
    NSLog(@"caching object succeed");
}];

//判斷緩存是否存在
[userInfoCache containsObjectForKey:key withBlock:^(NSString* _Nonnull key,BOOLcontains) {
  if(contains){
    NSLog(@"存在!");
  }
}];

//根據(jù)key讀取數(shù)據(jù)
[userInfoCache objectForKey:key withBlock:^(NSString* _Nonnull key,id  _Nonnull object) {
  NSLog(@"user_name : %@",object);
}];

//根據(jù)key移除緩存
[userInfoCache removeObjectForKey:key withBlock:^(NSString* _Nonnull key) {
    NSLog(@"remove user name %@",key);
}];

//移除所有緩存
[userInfoCache removeAllObjectsWithBlock:^{
    NSLog(@"removing all cache succeed");
}];

//移除所有緩存帶進(jìn)度
[userInfoCache removeAllObjectsWithProgressBlock:^(intremovedCount,inttotalCount) {
    NSLog(@"remove all cache objects: removedCount :%d  totalCount : %d",removedCount,totalCount);
} endBlock:^(BOOLerror) {
if(!error){
    NSLog(@"remove all cache objects: succeed");
}else{
      NSLog(@"remove all cache objects: failed");
}
}];

```swift

YYCache 架構(gòu)圖: (第一次嘗試使用MindNode,圖畫的不好~~~~)

yycache.png
  • YYCache:提供了最外層的接口,調(diào)用了YYMemoryCache與YYDiskCache的相關(guān)方法。
  • YYMemoryCache:負(fù)責(zé)處理容量小,相對(duì)高速的內(nèi)存緩存。線程安全,支持自動(dòng)和手動(dòng)清理緩存等功能。
  • _YYLinkedMap:YYMemoryCache使用的雙向鏈表類。
  • _YYLinkedMapNode:是_YYLinkedMap使用的節(jié)點(diǎn)類。
  • YYDiskCache:負(fù)責(zé)處理容量大,相對(duì)低速的磁盤緩存。線程安全,支持異步操作,自動(dòng)和手動(dòng)清理緩存等功能。
  • YYKVStorage:YYDiskCache的底層實(shí)現(xiàn)類,用于管理磁盤緩存。
  • YYKVStorageItem:內(nèi)置在YYKVStorage中,是YYKVStorage內(nèi)部用于封裝某個(gè)緩存的類
YYCache給用戶提供所有最外層的緩存操作接口,而這些接口的內(nèi)部?jī)?nèi)部實(shí)際上是調(diào)用了YYMemoryCache和YYDiskCache對(duì)象的相關(guān)方法。

因?yàn)閅YMemoryCache和YYDiskCache的實(shí)例作為YYCache的兩個(gè)公開的屬性,所以用戶無(wú)法直接使用YYMemoryCache和YYDiskCache對(duì)象,只能通過(guò)屬性的方式來(lái)間接使用它們。

YYCache的部分屬性和接口

interface.png

YYCache的接口實(shí)現(xiàn)

imp.png

從上面的接口實(shí)現(xiàn)可以看出:在YYCache中,永遠(yuǎn)都是先訪問(wèn)內(nèi)存緩存,然后再訪問(wèn)磁盤緩存(包括了寫入,讀取,查詢,刪除緩存的操作)。而且關(guān)于內(nèi)存緩存(_memoryCache)的操作,是不存在block回調(diào)的

YYMemoryCache

YYMemoryCache 操作類似于NSCache,它將需要緩存的對(duì)象與傳入的key關(guān)聯(lián)起來(lái)。
YYMemoryCache的內(nèi)部有:
緩存淘汰算法:使用LRU(least-recently-used) 算法來(lái)淘汰(清理)使用頻率較低的緩存。
緩存清理策略:使用三個(gè)維度來(lái)標(biāo)記,分別是count(緩存數(shù)量),cost(開銷),age(距上一次的訪問(wèn)時(shí)間)。YYMemoryCache提供了分別針對(duì)這三個(gè)維度的清理緩存的接口。用戶可以根據(jù)不同的需求(策略)來(lái)清理在某一維度超標(biāo)的緩存。
緩存淘汰算法的目的在于區(qū)分出使用頻率高和使用頻率低的緩存,當(dāng)緩存數(shù)量達(dá)到一定限制的時(shí)候會(huì)優(yōu)先清理那些使用頻率低的緩存。因?yàn)槭褂妙l率已經(jīng)比較低的緩存在將來(lái)的使用頻率也很有可能會(huì)低。

YYMemoryCache用一個(gè)鏈表節(jié)點(diǎn)類來(lái)保存某個(gè)單獨(dú)的內(nèi)存緩存的信息(鍵,值,緩存時(shí)間等),然后用一個(gè)雙向鏈表類來(lái)保存和管理這些節(jié)點(diǎn)。這兩個(gè)類的名稱分別是:
_YYLinkedMapNode:鏈表內(nèi)的節(jié)點(diǎn)類,可以看做是對(duì)某個(gè)單獨(dú)內(nèi)存緩存的封裝。
_YYLinkedMap:雙向鏈表類,用于保存和管理所有內(nèi)存緩存(節(jié)點(diǎn))
_YYLinkedMapNode可以被看做是對(duì)某個(gè)緩存的封裝:它包含了該節(jié)點(diǎn)上一個(gè)和下一個(gè)節(jié)點(diǎn)的指針,以及緩存的key
和對(duì)應(yīng)的值(對(duì)象),還有該緩存的開銷和訪問(wèn)時(shí)間。

/**
 A node in linked map.
 Typically, you should not use this class directly.
 鏈表內(nèi)的節(jié)點(diǎn)類,可以看做是對(duì)某個(gè)單獨(dú)內(nèi)存緩存的封裝
 */
@interface _YYLinkedMapNode : NSObject {
    @package
    __unsafe_unretained _YYLinkedMapNode *_prev; // retained by dic
    __unsafe_unretained _YYLinkedMapNode *_next; // retained by dic
    id _key;
    id _value;
    NSUInteger _cost;
    NSTimeInterval _time;
}
@end

_YYLinkedMap:

@interface _YYLinkedMap : NSObject {
    @package
    CFMutableDictionaryRef _dic;    // 用于存放節(jié)點(diǎn)
    NSUInteger _totalCost;          //總開銷
    NSUInteger _totalCount;         //節(jié)點(diǎn)總數(shù)
    _YYLinkedMapNode *_head;            // 鏈表的頭部結(jié)點(diǎn)
    _YYLinkedMapNode *_tail;        // 鏈表的尾部節(jié)點(diǎn)
    BOOL _releaseOnMainThread;          //是否在主線程釋放,默認(rèn)為NO
    BOOL _releaseAsynchronously;    //是否在子線程釋放,默認(rèn)為YES
}
//在鏈表頭部插入某節(jié)點(diǎn)
- (void)insertNodeAtHead:(_YYLinkedMapNode *)node;
//將鏈表內(nèi)部的某個(gè)節(jié)點(diǎn)移到鏈表頭部
- (void)bringNodeToHead:(_YYLinkedMapNode *)node;
//移除某個(gè)節(jié)點(diǎn)
- (void)removeNode:(_YYLinkedMapNode *)node;
//移除鏈表的尾部節(jié)點(diǎn)并返回它
- (_YYLinkedMapNode *)removeTailNode;
//移除所有節(jié)點(diǎn)(默認(rèn)在子線程操作)
- (void)removeAll;
@end

CFMutableDictionaryRef,用于保存節(jié)點(diǎn)的鍵值對(duì),它還持有了鏈表內(nèi)節(jié)點(diǎn)的總開銷,總數(shù)量,頭尾節(jié)點(diǎn)等數(shù)據(jù)。

[圖片上傳失敗...(image-875de1-1522245469574)]

_YYLinkedMap實(shí)現(xiàn)細(xì)節(jié):

插入結(jié)點(diǎn)(復(fù)習(xí)雙向鏈表的時(shí)候~~~~)

- (void)insertNodeAtHead:(_YYLinkedMapNode *)node {
    
    //設(shè)置該node的值
    CFDictionarySetValue(_dic, (__bridge const void *)(node->_key), (__bridge const void *)(node));
    
    //增加開銷和總緩存數(shù)量
    _totalCost += node->_cost;
    _totalCount++;
    
    if (_head) {
        
        //如果鏈表內(nèi)已經(jīng)存在頭節(jié)點(diǎn),則將這個(gè)頭節(jié)點(diǎn)賦給當(dāng)前節(jié)點(diǎn)的尾指針(原第一個(gè)節(jié)點(diǎn)變成了現(xiàn)第二個(gè)節(jié)點(diǎn))
        node->_next = _head;
        
        //將該節(jié)點(diǎn)賦給現(xiàn)第二個(gè)節(jié)點(diǎn)的頭指針(此時(shí)_head指向的節(jié)點(diǎn)是先第二個(gè)節(jié)點(diǎn))
        _head->_prev = node;
        
        //將該節(jié)點(diǎn)賦給鏈表的頭結(jié)點(diǎn)指針(該節(jié)點(diǎn)變成了現(xiàn)第一個(gè)節(jié)點(diǎn))
        _head = node;
        
    } else {
        
        //如果鏈表內(nèi)沒(méi)有頭結(jié)點(diǎn),說(shuō)明是空鏈表。說(shuō)明是第一次插入,則將鏈表的頭尾節(jié)點(diǎn)都設(shè)置為當(dāng)前節(jié)點(diǎn)
        _head = _tail = node;
    }
}

在雙向鏈表中:

  • 每個(gè)節(jié)點(diǎn)都有兩個(gè)分別指向前后節(jié)點(diǎn)的指針。所以說(shuō)每個(gè)節(jié)點(diǎn)都知道它前一個(gè)節(jié)點(diǎn)和后一個(gè)節(jié)點(diǎn)是誰(shuí)。
  • 鏈表的頭部節(jié)點(diǎn)指向它前面節(jié)點(diǎn)的指針為空;鏈表尾部節(jié)點(diǎn)指向它后側(cè)節(jié)點(diǎn)的指針也為空

將某個(gè)節(jié)點(diǎn)移動(dòng)到表頭

- (void)bringNodeToHead:(_YYLinkedMapNode *)node {
    //如果該節(jié)點(diǎn)已經(jīng)是鏈表頭部節(jié)點(diǎn),則立即返回,不做任何操作
    if (_head == node) return;
    if (_tail == node) {
        //如果該節(jié)點(diǎn)是鏈表的尾部節(jié)點(diǎn)
        //1. 將該節(jié)點(diǎn)的頭指針指向的節(jié)點(diǎn)變成鏈表的尾節(jié)點(diǎn)(將倒數(shù)第二個(gè)節(jié)點(diǎn)變成倒數(shù)第一個(gè)節(jié)點(diǎn),即尾部節(jié)點(diǎn))
        _tail = node->_prev;
        //2. 將新的尾部節(jié)點(diǎn)的尾部指針置空
        _tail->_next = nil;
    } else {
        //如果該節(jié)點(diǎn)是鏈表頭部和尾部以外的節(jié)點(diǎn)(中間節(jié)點(diǎn))
        //1. 將該node的頭指針指向的節(jié)點(diǎn)賦給其尾指針指向的節(jié)點(diǎn)的頭指針
        node->_next->_prev = node->_prev;
        //2. 將該node的尾指針指向的節(jié)點(diǎn)賦給其頭指針指向的節(jié)點(diǎn)的尾指針
        node->_prev->_next = node->_next;
    }
    //將原頭節(jié)點(diǎn)賦給該節(jié)點(diǎn)的尾指針(原第一個(gè)節(jié)點(diǎn)變成了現(xiàn)第二個(gè)節(jié)點(diǎn))
    node->_next = _head;
    //將當(dāng)前節(jié)點(diǎn)的頭節(jié)點(diǎn)置空
    node->_prev = nil;
    //將現(xiàn)第二個(gè)節(jié)點(diǎn)的頭結(jié)點(diǎn)指向當(dāng)前節(jié)點(diǎn)(此時(shí)_head指向的節(jié)點(diǎn)是現(xiàn)第二個(gè)節(jié)點(diǎn))
    _head->_prev = node;
    //將該節(jié)點(diǎn)設(shè)置為鏈表的頭節(jié)點(diǎn)
    _head = node;
}

移除鏈表中的某個(gè)節(jié)點(diǎn):

- (void)removeNode:(_YYLinkedMapNode *)node {
    
    //除去該node的鍵對(duì)應(yīng)的值
    CFDictionaryRemoveValue(_dic, (__bridge const void *)(node->_key));
    
    //減去開銷和總緩存數(shù)量
    _totalCost -= node->_cost;
    _totalCount--;
    
    //節(jié)點(diǎn)操作
    //1. 將該node的頭指針指向的節(jié)點(diǎn)賦給其尾指針指向的節(jié)點(diǎn)的頭指針
    if (node->_next) node->_next->_prev = node->_prev;
    
    //2. 將該node的尾指針指向的節(jié)點(diǎn)賦給其頭指針指向的節(jié)點(diǎn)的尾指針
    if (node->_prev) node->_prev->_next = node->_next;
    
    //3. 如果該node就是鏈表的頭結(jié)點(diǎn),則將該node的尾部指針指向的節(jié)點(diǎn)賦給鏈表的頭節(jié)點(diǎn)(第二變成了第一)
    if (_head == node) _head = node->_next;
    
    //4. 如果該node就是鏈表的尾節(jié)點(diǎn),則將該node的頭部指針指向的節(jié)點(diǎn)賦給鏈表的尾節(jié)點(diǎn)(倒數(shù)第二變成了倒數(shù)第一)
    if (_tail == node) _tail = node->_prev;
}

查找/緩存/更新某個(gè)對(duì)象

//是否包含某個(gè)緩存對(duì)象
- (BOOL)containsObjectForKey:(id)key {
    //嘗試從內(nèi)置的字典中獲得緩存對(duì)象
    if (!key) return NO;
    pthread_mutex_lock(&_lock);
    BOOL contains = CFDictionaryContainsKey(_lru->_dic, (__bridge const void *)(key));
    pthread_mutex_unlock(&_lock);
    return contains;
}
//獲取某個(gè)緩存對(duì)象
- (id)objectForKey:(id)key {
    
    if (!key) return nil;
    
    pthread_mutex_lock(&_lock);
    _YYLinkedMapNode *node = CFDictionaryGetValue(_lru->_dic, (__bridge const void *)(key));
    if (node) {
        //如果節(jié)點(diǎn)存在,則更新它的時(shí)間信息(最后一次訪問(wèn)的時(shí)間)
        node->_time = CACurrentMediaTime();
        [_lru bringNodeToHead:node];
    }
    pthread_mutex_unlock(&_lock);
    
    return node ? node->_value : nil;
}
//寫入某個(gè)緩存對(duì)象,開銷默認(rèn)為0
- (void)setObject:(id)object forKey:(id)key {
    [self setObject:object forKey:key withCost:0];
}
//寫入某個(gè)緩存對(duì)象,并存入緩存開銷
- (void)setObject:(id)object forKey:(id)key withCost:(NSUInteger)cost {
    
    if (!key) return;
    
    if (!object) {
        [self removeObjectForKey:key];
        return;
    }
    
    pthread_mutex_lock(&_lock);
    
    _YYLinkedMapNode *node = CFDictionaryGetValue(_lru->_dic, (__bridge const void *)(key));
    NSTimeInterval now = CACurrentMediaTime();
    
    if (node) {
        //如果存在與傳入的key值匹配的node,則更新該node的value,cost,time,并將這個(gè)node移到鏈表頭部
        
        //更新總cost
        _lru->_totalCost -= node->_cost;
        _lru->_totalCost += cost;
        
        //更新node
        node->_cost = cost;
        node->_time = now;
        node->_value = object;
        
        //將node移動(dòng)至鏈表頭部
        [_lru bringNodeToHead:node];
        
    } else {
        
        //如果不存在與傳入的key值匹配的node,則新建一個(gè)node,將key,value,cost,time賦給它,并將這個(gè)node插入到鏈表頭部
        //新建node,并賦值
        node = [_YYLinkedMapNode new];
        node->_cost = cost;
        node->_time = now;
        node->_key = key;
        node->_value = object;
        
        //將node插入至鏈表頭部
        [_lru insertNodeAtHead:node];
    }
    
    //如果cost超過(guò)了限制,則進(jìn)行刪除緩存操作(從鏈表尾部開始刪除,直到符合限制要求)
    if (_lru->_totalCost > _costLimit) {
        dispatch_async(_queue, ^{
            [self trimToCost:_costLimit];
        });
    }
    
    //如果total count超過(guò)了限制,則進(jìn)行刪除緩存操作(從鏈表尾部開始刪除,刪除一次即可)
    if (_lru->_totalCount > _countLimit) {
        _YYLinkedMapNode *node = [_lru removeTailNode];
        if (_lru->_releaseAsynchronously) {
            dispatch_queue_t queue = _lru->_releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
            dispatch_async(queue, ^{
                [node class]; //hold and release in queue
            });
        } else if (_lru->_releaseOnMainThread && !pthread_main_np()) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [node class]; //hold and release in queue
            });
        }
    }
    pthread_mutex_unlock(&_lock);
}
//移除某個(gè)緩存對(duì)象
- (void)removeObjectForKey:(id)key {
    
    if (!key) return;
    
    pthread_mutex_lock(&_lock);
    _YYLinkedMapNode *node = CFDictionaryGetValue(_lru->_dic, (__bridge const void *)(key));
    if (node) {
    
        //內(nèi)部調(diào)用了鏈表的removeNode:方法
        [_lru removeNode:node];
        if (_lru->_releaseAsynchronously) {
            dispatch_queue_t queue = _lru->_releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
            dispatch_async(queue, ^{
                [node class]; //hold and release in queue
            });
        } else if (_lru->_releaseOnMainThread && !pthread_main_np()) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [node class]; //hold and release in queue
            });
        }
    }
    pthread_mutex_unlock(&_lock);
}
//內(nèi)部調(diào)用了鏈表的removeAll方法
- (void)removeAllObjects {
    pthread_mutex_lock(&_lock);
    [_lru removeAll];
    pthread_mutex_unlock(&_lock);
}

YYDiskCache

YYDiskCache處理容量大,相對(duì)低速的磁盤緩存。線程安全,支持異步操作。作為YYCache的第二級(jí)緩存,

與第一級(jí)緩存YYMemoryCache的相同點(diǎn)是:

  • 都具有查詢,寫入,讀取,刪除緩存的接口。
  • 不直接操作緩存,也是間接地通過(guò)另一個(gè)類(YYKVStorage)來(lái)操作緩存。
  • 它使用LRU算法來(lái)清理緩存。
  • 支持按 cost,count 和 age 這三個(gè)維度來(lái)清理不符合標(biāo)準(zhǔn)的緩存。

它與YYMemoryCache不同點(diǎn)是:

  • 根據(jù)緩存數(shù)據(jù)的大小來(lái)采取不同的形式的緩存:
  • 數(shù)據(jù)庫(kù)sqlite: 針對(duì)小容量緩存,緩存的data和元數(shù)據(jù)都保存在數(shù)據(jù)庫(kù)里。
  • 除了 cost,count 和 age 三個(gè)維度之外,還添加了一個(gè)磁盤容量的維度。
// 緩存方式
typedef NS_ENUM(NSUInteger, YYKVStorageType) {
    YYKVStorageTypeFile = 0,
    YYKVStorageTypeSQLite = 1,
    YYKVStorageTypeMixed = 2,
};

緩存的大致邏輯

  1. 首先判斷傳入的key和value是否符合要求,如果不符合要求,則立即返回NO,緩存失敗。
  2. 再判斷是否type==YYKVStorageTypeFile并且文件名為空字符串(或nil):如果是,則立即返回NO,緩存失敗。

判斷filename是否為空字符串:

  1. 如果不為空:
    寫入文件,并將緩存的key,等信息寫入數(shù)據(jù)庫(kù),但是不將key對(duì)應(yīng)的data寫入數(shù)據(jù)庫(kù)。
  2. 如果為空:
    如果緩存類型為YYKVStorageTypeSQLite:將緩存文件刪除
    如果緩存類型不為YYKVStorageTypeSQLite:則將緩存的key和對(duì)應(yīng)的data等其他信息存入數(shù)據(jù)庫(kù)。

YYKVStorage

YYKVStorage實(shí)例負(fù)責(zé)保存和管理所有磁盤緩存。和YYMemoryCache里面的_YYLinkedMap將緩存封裝成節(jié)點(diǎn)類_YYLinkedMapNode類似,YYKVStorage也將某個(gè)單獨(dú)的磁盤緩存封裝成了一個(gè)類,這個(gè)類就是YYKVStorageItem,它保存了某個(gè)緩存所對(duì)應(yīng)的一些信息(key, value, 文件名,大小等等):

YYKVStorageItem結(jié)構(gòu)包含了鍵/值/文件名/值大小/時(shí)間戳/擴(kuò)展數(shù)據(jù)等等字段

/**
 YYKVStorageItem is used by `YYKVStorage` to store key-value pair and meta data.
 Typically, you should not use this class directly.
 YYKVStorage也將某個(gè)單獨(dú)的磁盤緩存封裝成了一個(gè)類,這個(gè)類就是YYKVStorageItem,它保存了某個(gè)緩存所對(duì)應(yīng)的一些信息(key, value, 文件名,大小等等)
 */
@interface YYKVStorageItem : NSObject
@property (nonatomic, strong) NSString *key;                ///< key
@property (nonatomic, strong) NSData *value;                ///< value
@property (nullable, nonatomic, strong) NSString *filename; ///< filename (nil if inline)
@property (nonatomic) int size;                             ///< value's size in bytes
@property (nonatomic) int modTime;                          ///< modification unix timestamp
@property (nonatomic) int accessTime;                       ///< last access unix timestamp
@property (nullable, nonatomic, strong) NSData *extendedData; ///< extended data (nil if no extended data)
@end

還有一些方法來(lái)操作數(shù)據(jù)

//YYKVStorage.h
- (BOOL)saveItem:(YYKVStorageItem *)item;
- (BOOL)saveItemWithKey:(NSString *)key value:(NSData *)value;
- (BOOL)saveItemWithKey:(NSString *)key
                  value:(NSData *)value
               filename:(nullable NSString *)filename
           extendedData:(nullable NSData *)extendedData;
#pragma mark - Remove Items
- (BOOL)removeItemForKey:(NSString *)key;
- (BOOL)removeItemForKeys:(NSArray<NSString *> *)keys;
- (BOOL)removeItemsLargerThanSize:(int)size;
- (BOOL)removeItemsEarlierThanTime:(int)time;
- (BOOL)removeItemsToFitSize:(int)maxSize;
- (BOOL)removeItemsToFitCount:(int)maxCount;

總結(jié)一下:

1. 為什么使用雙向鏈表?
  1. 雙向鏈表可以知道前后節(jié)點(diǎn),所以如果想移動(dòng)其中一個(gè)節(jié)點(diǎn)的話,其前后的節(jié)點(diǎn)不好做銜接。
  2. 其節(jié)點(diǎn)的關(guān)聯(lián)僅僅是靠指針,所以對(duì)于插入和刪除操作會(huì)很便利,而類似數(shù)組的方式尋址操作缺比較費(fèi)時(shí)。由于在LRU策略中會(huì)有非常多的移動(dòng),插入和刪除節(jié)點(diǎn)的操作,使用雙向鏈表是比較有優(yōu)勢(shì)的。
2. 使用CFDictionary而沒(méi)有用NSDictionary來(lái)實(shí)現(xiàn)?

CFDictionary 更加底層,更快.

3. 為什么內(nèi)存緩存使用互斥鎖?而磁盤緩存使用信號(hào)量?

作者在最初使用的是自旋鎖(OSSpinLock)作為內(nèi)存緩存的線程鎖,但是后來(lái)得知其不夠安全,所以退而求其次,使用了pthread_mutex 這篇文章有說(shuō)明
網(wǎng)上說(shuō):但當(dāng)信號(hào)總量設(shè)為 1 時(shí)也可以當(dāng)作鎖來(lái)。在沒(méi)有等待情況出現(xiàn)時(shí),它的性能比 pthread_mutex 還要高,但一旦有等待情況出現(xiàn)時(shí),性能就會(huì)下降許多。相對(duì)于 OSSpinLock 來(lái)說(shuō),它的優(yōu)勢(shì)在于等待時(shí)不會(huì)消耗 CPU 資源。對(duì)磁盤緩存來(lái)說(shuō),它比較合適。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一個(gè)人靜靜在陽(yáng)臺(tái)上,兩手雙靠攏,下巴放在手臂上,看著這一片綠色的花草樹木,心里很平靜。 寂靜的晚上一個(gè)人仰望星空,...
    周心愿閱讀 337評(píng)論 0 0
  • 背景 在日常開發(fā)的一些業(yè)務(wù)場(chǎng)景中,如果涉及到一些敏感信息(如:付款的二維碼或條形碼等),而我們不希望相關(guān)敏感信息被...
    Daved閱讀 27,558評(píng)論 11 18
  • 2017~11~16 信陽(yáng)市七中 學(xué)校教育是“葉”的教育,家庭教育才是“根”的教育。真正的家庭教育是...
    善默勤容閱讀 702評(píng)論 0 0

友情鏈接更多精彩內(nèi)容