談談iOS中的鎖

来源:http://www.cnblogs.com/zhanggui/archive/2016/11/05/6033273.html
-Advertisement-
Play Games

近日工作不是太忙,剛好有時間瞭解一些其他東西,本來打算今天上午去體檢,但是看看天氣還是明天再去吧,也有很大一個原因:就是周六沒有預約上!閑話少說,這裡簡單對鎖來個簡單介紹分享。 ...


1 前言

近日工作不是太忙,剛好有時間瞭解一些其他東西,本來打算今天上午去體檢,但是看看天氣還是明天再去吧,也有很大一個原因:就是周六沒有預約上!閑話少說,這裡簡單對鎖來個簡單介紹分享。

2 目錄
  • 第一部分:什麼是鎖
  • 第二部分:鎖的分類
  • 第三部分:鎖的作用
  • 第四部分:iOS中鎖的實現

    第一部分:什麼是鎖

    從小就知道鎖,就是家裡門上的那個鎖,用來防止盜竊的鎖。它還有鑰匙,用於開鎖。不過這裡的鎖,並不是小時候認知的鎖,而是站在程式員的角度的鎖。這裡我就按照我的理解來介紹一下鎖。
    在電腦科學中,鎖是一種同步機制,用於在存在多線程的環境中實施對資源的訪問限制。你可以理解成它用於排除併發的一種策略。看例子

    if (lock == 0) {
    lock = myPID;
    }

    上面這段代碼並不能保證這個任務有個鎖,因此它可以在同一時間被多個任務執行。這個時候就有可能多個任務都檢測到lock是空閑的,因此兩個或者多個任務都將嘗試設置lock,而不知道其他的任務也在嘗試設置lock。這個時候就會出問題了。
    再看看這段代碼:

    class Acccount {
    long val = 0;  //這裡不可在其他方法修改,只能通過add/minus修改
    object thisLock = new object();
    public void add(const long x) {
    lock(thisLock) {
        val +=x;
    }
    }
    public void minus(const long x) {
    lock(thisLock) {
        val -=x;
        }
    }
    }

    這樣就能防止多個任務去修改val了,(這裡註意,如果val是public的,那個也會導致一些問題)。

    第二部分:鎖的分類

    鎖根據不同的性質可以分成不同的類。
    在WiKiPedia介紹中,一般的鎖都是建議鎖,也就四每個任務去訪問公共資源的時候,都需要取得鎖的資訊,再根據鎖資訊來確定是否可以存取。若存取對應資訊,鎖的狀態會改變為鎖定,因此其他線程不會訪問該資源,當結束訪問時,鎖會釋放,允許其他任務訪問。有些系統有強制鎖,若未經授權的鎖訪問鎖定的資料,在訪問時就會產生異常。
    在iOS中,鎖分為遞歸鎖、條件鎖、分散式鎖、一般鎖(這裡是看著NSLock類裡面的分類劃分的)。
    對於資料庫的鎖分類:

分類方式 分類
按鎖的粒度劃分 表級鎖、行級鎖、頁級鎖
按鎖的級別劃分 共用鎖、排他鎖
按加鎖方式劃分 自動鎖、顯示鎖
按鎖的使用方式劃分 樂觀鎖、悲觀鎖
按操作劃分 DML鎖、DDL鎖

這裡就不在詳細介紹了,感興趣的大家可以自己查閱相關資料。

第三部分:鎖的作用

這個比較通俗來講:就是為了防止在多線程(多任務)的情況下對共用資源(臨界資源)的臟讀或者臟寫。也可以理解為:執行多線程時用於強行限制資源訪問的同步機制,即併發控制中保證互斥的要求。

第四部分:iOS中鎖的實現

先看看iOS中NSLock類的.h文件。這裡就不在寫上來了。從代碼中可以看出,該類分成了幾個子類:NSLock、NSConditionLock、NSRecursiveLock以及NSCondition。然後有一個NSLocking的協議:

@protocol NSLocking
- (void)lock;
- (void)unlock;
@end

這幾個子類都遵循了NSLock的協議,這裡簡單介紹一下其中的幾個方法:
對於tryLock方法,嘗試獲取一個鎖,並且立刻返回Bool值,YES表示獲取了鎖,NO表示沒有獲取鎖失敗。 lockBeforeDate:方法,在某個時刻之前獲取鎖,如果獲取成功,則返回YES,NO表示獲取鎖失敗。接下來就讓我們看一下iOS中實現鎖的方式:

方式1 使用NSLock類
- (void)nslockDemo {
    NSLock *myLock = [[NSLock alloc] init];
    _testLock = [[TestLock alloc] init];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [myLock lock];
        [_testLock method1];
        sleep(5);
        [myLock unlock];
        if ([myLock tryLock]) {
            NSLog(@"可以獲得鎖");
        }else {
            NSLog(@"不可以獲得所");
        }
    });
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        if ([myLock tryLock]) {
            NSLog(@"---可以獲得鎖");
        }else {
            NSLog(@"----不可以獲得所");
        }
        [myLock lock];
        [_testLock method2];
        [myLock unlock];
    });
}
方式2 使用@synchorize
- (void)synchronizeDemo {
    _testLock = [[TestLock alloc] init];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        @synchronized (_testLock) {
            [_testLock method1];
            sleep(5);
        }
    });
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        @synchronized (_testLock) {
            
            [_testLock method2];
        }
    });
}

對於synchorize指令中使用的testLock為該鎖標示,只有標示相同的時候才滿足鎖的效果。它的優點是不用顯式地創建鎖,便可以實現鎖的機制。但是它會隱式地添加異常處理程式來保護代碼,該程式在拋出異常的時候自動釋放鎖。

方式3 使用gcd
- (void)gcdDemo {
    _testLock = [[TestLock alloc] init];
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        [_testLock method1];
        sleep(5);
        dispatch_semaphore_signal(semaphore);
    });
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        [_testLock method2];
        dispatch_semaphore_signal(semaphore);
    });

}
方式4 使用phtread
- (void)pthreadDemo {
    _testLock = [[TestLock alloc] init];
    
    __block pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, NULL);
    
    //線程1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        pthread_mutex_lock(&mutex);
        [_testLock method1];
        sleep(5);
        pthread_mutex_unlock(&mutex);
    });
    
    //線程2
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        pthread_mutex_lock(&mutex);
        [_testLock method2];
        pthread_mutex_unlock(&mutex);
    });
}

pthread_mutex_t定義在pthread.h,所以記得#include。

3 性能對比

這裡簡單寫一個小程式來進行四種方式的性能對比,這裡再固定次數內進行了加鎖解鎖,然後輸出用時,結果如下(測試1、2執行次數不一樣:測試1 < 測試2):

測試1
2016-11-05 15:27:52.595 LockDemo[4394:202297] NSLock times:0.871843
2016-11-05 15:27:56.335 LockDemo[4394:202297] synthorize times:3.738939
2016-11-05 15:27:56.691 LockDemo[4394:202297] gcd times:0.355344
2016-11-05 15:27:57.328 LockDemo[4394:202297] pthread times:0.636815
2016-11-05 15:27:57.559 LockDemo[4394:202297] OSSPinLock times:0.231013
2016-11-05 15:27:57.910 LockDemo[4394:202297] os_unfair_lock times:0.350615
測試2
2016-11-05 15:30:54.123 LockDemo[4454:205180] NSLock times:1.908103
2016-11-05 15:31:02.112 LockDemo[4454:205180] synthorize times:7.988547
2016-11-05 15:31:02.905 LockDemo[4454:205180] gcd times:0.792113
2016-11-05 15:31:04.372 LockDemo[4454:205180] pthread times:1.466987
2016-11-05 15:31:04.870 LockDemo[4454:205180] OSSPinLock times:0.497487
2016-11-05 15:31:05.637 LockDemo[4454:205180] os_unfair_lock times:0.767569

這裡還測試了OSSPinLock(此類已經被os_unfair_lock所替代)。結果如下:
synthorize > NSLock > pthread > gcd > os_unfair_lock >OSSPinLock
這裡:
synthorize內部會添加異常處理,所以耗時。
pthread_mutex底層API,處理能力不錯。
gcd系統封裝的C代碼效果比pthread好。

4 總結

簡單就介紹這麼多。

5 參考文檔:

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • html部分 <!DOCTYPE html> <!--下麵三個百分比都是為了實現後期項目優化的時候,實現自適應屏幕的寬度和高度--> <html style="height: 100%;"> <!--這個需要HTML標簽上也得加上style="height:100%"才行,要不然會顯示一半,經常用C ...
  • 今天項目需要用到旋轉木馬輪播功能,需要顯示個可以切換的選項,這幾個選項也許是圖片,也許是文字,也許是一個iframe頁面,也有可能是圖文混排,還可能需要支持調用介面數據,需要顯示多條信息,最少3條,最多不限,可能有10條,可能有10000條,於是就有了下麵這個實現方法,看上去已經很完美了(樣式和具體... ...
  • 簡介 技術一般水平有限,有什麼錯的地方,望大家指正。 sessionStorage、localStorage、cookie這三個是我們在瀏覽器端用來存儲數據的,cookie使用起來較為繁瑣以後進行總結,主要介紹一下sessionStorage和localStorage的用法。sessionStora ...
  • 恢復內容開始 當我們註冊或者登錄要用郵箱格式時會顯示郵箱尾碼的提示下拉框 效果如圖所示 主要介紹了JS輸入用戶名自動顯示郵箱尾碼列表的方法,可實現自動顯示郵箱尾碼名列表的功能, 原理是:一個輸入框 當我輸入任何字的時候 自動下拉相應的郵箱提示,在輸入框輸入11的時候 下拉框有所有11的郵箱 輸入其他 ...
  • 工欲善其事,必先利其器。以下介紹一些常用的Android Plugin,有助於開發。 1、adb-idea 支持在AS面板中,執行ADB命令。不過如果用慣命令行的話,可以不安裝; 2、android-parcelable-intellij-plugin parcelable 代碼補全,省時省力; 3 ...
  • 1.SwipeRefreshLayout是Google在support v4 19.1版本的library更新的一個下拉刷新組件,實現刷新效果更方便。 弊端:只有下拉 2.在xml文件中引用android.support.v4.widget.SwipeRefreshLayout控制項,在裡面可以放置任 ...
  • 1、Android Log簡介; 在程式中輸出日誌,使用 android.util.Log 類。該類提供了若幹靜態方法: Log.v(String tag, String msg); // 任何消息都會輸出 Log.d(String tag, String msg); // 僅輸出debug調試的意 ...
  • 1.簡介 RecyclerView是一種新的視圖組,目標是為任何基於適配器的視圖提供相似的渲染方式。它被作為ListView和GridView控制項的繼承者,在最新的support-V7版本中提供支持。RecyclerView架構,提供了一種插拔式的體驗,高度的解耦,異常的靈活,通過設置它提供的不同L ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...