1. 程式人生 > >Linux下sqlite3多執行緒和序列模式

Linux下sqlite3多執行緒和序列模式

sqlite3支援三種模式:單執行緒模式,多執行緒模式和序列模式。

  • 模式可在編譯,啟動時或執行時設定,一般來講,啟動時的設定會覆蓋編譯時的設定,執行時則會覆蓋啟動時或編譯時的設定。但是一旦單執行緒模式被設定之後就不能再被覆蓋了。

  • 編譯時可通過SQLITE_THREADSAFE設定模式。sqlite3標準 發行版本預設設定為SQLITE_THREADSAFE=1, 即序列模式。SQLITE_THREADSAFE=2為多執行緒模式,SQLITE_THREADSAFE=0為單執行緒模式,當設定為0時,即使初始化或執行時設定為其他模式,也會保持單執行緒模式。

  • 啟動時是指在sqlite3在初始化之前呼叫sqlite3_config()函式設定,引數為SQLITE_CONFIG_SINGLETHREAD,SQLITE_CONFIG_MULTITHREAD或SQLITE_CONFIG_SERIALIZED。

  • sqlite3初始化指的是呼叫sqlite3_initalize(),該函式會在呼叫sqlite3_open_v2()時呼叫。執行時也就是程式第一次(僅第一次呼叫有效)呼叫該函式建立資料庫連線時,通過設定第三個引數為設定不同模式,SQLITE_OPEN_NOMUTEX為多執行緒模式,SQLITE_OPEN_FULLMUTEX為序列模式。

序列模式

序列模式支援多執行緒操作,但是必須統一使用一個全域性的資料庫連線,這一點非常重要。序列模式會開啟sqlite3所有的鎖,在同一時刻保證只有一個執行緒能訪問。這裡可以理解為只有一條指向資料庫的連線,多個執行緒的請求將會在該連線上序列傳輸。

多執行緒模式

  1. 多執行緒模式支援執行緒併發操作,但也有例外,因為在該模式下,sqlite3打開了bCoreMutex鎖,關閉了bFullMutex鎖,也就禁止了多個執行緒併發使用同一個資料庫連線和perpared statement, perpared statement可以簡單的使用訊號量進行互斥。

  2. 使用多執行緒模式,除了需要設定模式外,還必須在執行資料庫操作前呼叫sqlite3_busy_handler()或sqlite3_busy_timeout() 。這兩個函式會判斷sqlite是否處於SQLITE_BUSY狀態,是的話將進行sleep等待。區別在於sqlite3_busy_handler()需要自己實現等待的處理,而sqlite3_busy_timeout()實際上是呼叫了sqlite3_busy_handler()並使用一個預設的等待處理函式。

  3. sqlite3_busy_timeout()通過指定最大超時時間進行等待。根據sqlite3_busy_timeout()原始碼,需要注意,如果系統未定義HAVE_USLEEP或定定義為false,則超時時間必須指定為大於1000且是它的整數倍。
    無論有無定義,使用sqlite3_busy_timeout()的等待時間都是該函式的演算法實現,所以如果需要完全按照自己的需求決定等待時間,可以使用sqlite3_busy_handler(),該函式需要自己實現等待處理函式,處理函式中即可指定等待時間。

  4. sqlite3_busy_timeout() 原始碼:

static int sqliteDefaultBusyCallback(  
    void *ptr,               /* Database connection */  
    int count                /* Number of times table has been busy */  
)  
{  
#if SQLITE_OS_WIN || (defined(HAVE_USLEEP) && HAVE_USLEEP)  
    static const u8 delays[] =  
        { 1, 2, 5, 10, 15, 20, 25, 25,  25,  50,  50, 100 };  
    static const u8 totals[] =  
        { 0, 1, 3,  8, 18, 33, 53, 78, 103, 128, 178, 228 };  
# define NDELAY (sizeof(delays)/sizeof(delays[0]))  
    sqlite3 *db = (sqlite3 *)ptr;  
    int timeout = db->busyTimeout;  
    int delay, prior;  
    assert( count>=0 );  
    if( count < NDELAY ){  
        delay = delays[count];  
        prior = totals[count];  
    }else{  
        delay = delays[NDELAY-1];  
        prior = totals[NDELAY-1] + delay*(count-(NDELAY-1));  
    }  
    if( prior + delay > timeout ){  
        delay = timeout - prior;  
        if( delay<=0 ) return 0;  
    }  
    sqlite3OsSleep(db->pVfs, delay*1000);  
    return 1;  
#else  
    sqlite3 *db = (sqlite3 *)ptr;  
    int timeout = ((sqlite3 *)ptr)->busyTimeout;  
    if( (count+1)*1000 > timeout ){  
        return 0;//1000>timeout,so timeout must bigger than 1000  
    }  
    sqlite3OsSleep(db->pVfs, 1000000);//1000ms  
    return 1;  
#endif  
}  

int sqlite3_busy_timeout(sqlite3 *db, int ms){  
    if( ms>0 ){  
        db->busyTimeout = ms;  
        sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db);  
    }else{  
        sqlite3_busy_handler(db, 0, 0);  
    }  
    return SQLITE_OK;  
}

Exmaple

    // 判斷編譯時模式,設定啟動時模式為多執行緒模式
    int mode = sqlite3_threadsafe();
    if (mode == 0) {
        AIO_LOG_W("SQLite database is not compiled to be threadsafe");
        return AIO_ERR;
    }

    int ret = sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
    if (ret != SQLITE_OK) {
        AIO_LOG_E("setting sqlite thread safe mode to multithread failed: %d", ret);
        return AIO_ERR;
    }

    ... ...

    // 設定SQLITE_BUSY 處理,使用sqlite3_busy_timeout()

    #define SQLITE_EXE(db, sql, callback, ptr, msg) \
    {       \
        rc = sqlite3_busy_timeout(db, 10 * MSEC_PER_SEC); \
        if (rc != SQLITE_OK) {  \
            AIO_LOG_E("SQL error: %d, file: %s. func: %s, line: %d.\n", \
                      rc, __FILE__, __func__, __LINE__);    \
        }   \
        rc = sqlite3_exec(db, sql, callback, ptr, &msg);  \
        if (rc != SQLITE_OK) {  \
            AIO_LOG_E("SQL error: %s, file: %s. func: %s, line: %d.\n", \
                      msg, __FILE__, __func__, __LINE__); \
            sqlite3_free(msg);      \
        }       \
    }

    // 設定SQLITE_BUSY 處理,使用sqlite3_busy_handler()
    static int cb_sql_busy(void *ptr, int count)
    {
        int timeout = *((int *)ptr);

        (void)usleep(timeout);
        return 1;
    }

    static int sql_busy_check(sqlite3 *db, int ms)
    {
        if( ms > 0 )
            sqlite3_busy_handler(db, cb_sql_busy, (void*)&ms);
        else
            sqlite3_busy_handler(db, 0, 0);  

        return SQLITE_OK;
    }

    int my_sqlite_exe(...) {
        rc = sql_busy_check(db, 100);
        ... ...
        rc = sqlite3_exec(db, sql, NULL, NULL, &msg);
        ... ...
    }

相關推薦

Linuxsqlite3執行序列模式

sqlite3支援三種模式:單執行緒模式,多執行緒模式和序列模式。 模式可在編譯,啟動時或執行時設定,一般來講,啟動時的設定會覆蓋編譯時的設定,執行時則會覆蓋啟動時或編譯時的設定。但是一旦單執行緒模式被設定之後就不能再被覆蓋了。 編譯時可通過SQLITE_T

Linuxc++執行互斥鎖

一、多執行緒 多執行緒使用的是pthread庫,寫程式的時候需要引入標頭檔案pthread.h, g++編譯的時候需要加上該庫的依賴“-lpthread”。 1 先看程式便於理解,程式碼下面有對註釋的解釋。下面的程式碼含義是建立兩個執行緒,一個執行緒去計算某

linux執行實現socket伺服器客戶端的非同步通訊

前面介紹了用select函式來實現socket的非同步收發資料,但是select函式也有一些缺陷,要使socket能持續地通訊,select必須不停地檢測,這樣程序就會一直阻塞在這裡,限制了功能的擴充套件,這裡我們用多執行緒的方式,另建立兩個執行緒用來發送/接收

linux執行/程序同步/通訊機制

while (1) { //這個mutex主要是用來保證pthread_cond_wait的併發性 pthread_mutex_lock(&mtx); while (head == NULL) {

Linux執行程式設計二(執行的同步與互斥)

一、什麼叫做執行緒的同步與互斥?為什麼需要同步與互斥? 1、同步與互斥 互斥:是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。 同步:是指在互斥的基礎上(大多數情況),通過其它機制

樹莓派3B LinuxC++執行程式設計

下面的程式碼手動建立了兩個執行緒,一個執行緒是讀取串列埠的資料,另一個執行緒是通過UDP來讀取網路通訊收到的資料。加上main函式的執行緒,一共三個執行緒。 先簡單講一下多執行緒的建立, pthread_t serial; int ser =

linux核心執行的簡單實現

#include<linux/init.h> #include<linux/module.h> #include<linux/kernel.h> #include<linux/delay.h> #include<linux/wait.h> #incl

Linux執行程式設計

我們編譯此程式: gcc example1.c -lpthread -o example1 執行example1,我們得到如下結果: This is the main process. This is a pthread. This is the main process. This is the ma

Solaris10 執行Mysql執行連線

1. Solairs下的多執行緒 執行緒分成兩種,一種是POSIX格式的(使用 pthread.h),一種是Solairs格式的(thread.h),建議使用 POSIX格式。 int pthread_create(pthread_t *restrict th

day24總結_執行設計模式

1、多執行緒 ①、JDK5以後的針對執行緒的鎖定操作和釋放操作 // 定義鎖物件 private Lock lock = new ReentrantLock(); // 加鎖 lock.lock(); // 釋放鎖 lock.unlock(); ②、死鎖問題的描述和程式碼體現 *死鎖:兩個或

Linux 執行程序的區別(小結)

最近學習Linux,看到“hairetz的專欄”的帖子不錯,特轉來大家一起學習。 很想寫點關於多程序和多執行緒的東西,我確實很愛他們。但是每每想動手寫點關於他們的東西,卻總是求全心理作祟,始終動不了手。 今天終於下了決心,寫點東西,以後可以再修修補補也無妨。一.為何需要多程序(或者多執行緒),為何需

Linux作業系統執行程式設計詳細解析----條件變數pthread_cond_t

在多執行緒程式設計下,常常出現A執行緒要等待B執行緒條件完成後再繼續進行,這裡等待方式有兩種: 1.使用鎖+輪詢        使用這種方法可以很簡單的實現,但是會有一定的效能消耗,其還有一個點要好好把握,就是一次輪詢沒有結果後相隔多久進行下一次的輪詢,間隔時間太短,消耗

執行“鎖”的應用

  假設這樣一種情況:有多個執行緒(或多核)需要在共享資料A滿足某一條件時,對A進行操作. 以下舉例兩種實現 Fun_1() { lock()--------------1.1   Result=Check(A)-----1.2   Unlock()------------

核CPU單核CPU執行

多核CPU和單核CPU下的多執行緒 多執行緒程式設計是現代軟體技術中很重要的一個環節。要弄懂多執行緒,這就要牽涉到多程序?當然,要了解到多程序,就要涉及到作業系統。不過大家也不要緊張,聽我慢慢道來。這其中的環節其實並不複雜。 單核CPU下的多執行緒 在沒有出現多核CPU之前,我們

作業系統實驗——序列執行執行池三種方式計算矩陣乘法

package cn.edu.seu.yujun.OS; /** * * @author Fish * Date:2015/4/7 */ public class WorkThread implements Runnable { private int start;//計算開始位置,以此區分工作執

Linux】GDB除錯執行程序以及Core檔案

GDB偵錯程式 基本概念 GDB是GNU開源組織釋出的一個強大的UNIX下的程式除錯工具。或許,各位比較喜歡那種圖形介面方式的,像VC、BCB等IDE的除錯,但如果你是在UNIX平臺下做軟體,你會發現

如何在WindowsLinux獲取當前執行的ID號

Linux下獲取當前執行緒ID號函式: pthread_t pthread_self(); 返回:當前執行緒的ID號 pthread_t 資料型別的定義如下: typedef unsigned long int pthread_t; sizeof(pthread_t) =

Linux:使用執行程式設計訊息佇列,實現兩個程序之間的聊天

思路: 一個檔案:建立一個執行緒和主函式,或者建立兩個執行緒主函式呼叫(我用這種)。 建立兩個訊息佇列, 一共兩個檔案,兩個佇列,四個程序 a.c    一個程序寫(訊息型別為1)   ---->>佇列     一個程序讀(訊息型別為2) b.c   一

VC6.0建立執行的方法注意的事項

#include<stdio.h> #include <process.h> #include <stdio.h> #include <windows.h> DWORD _stdcall ThreadProc(LPVOID l

執行程式設計之Linux環境執行(一)——好文

一、Linux環境下的執行緒   相對於其他作業系統,Linux系統核心只提供了輕量級程序的支援,並未實現執行緒模型。Linux是一種“多程序單執行緒”的作業系統,Linux本身只有程序的概念,而其所謂的“執行緒”本質上在核心裡仍然是程序。      程序是資源分配的單位,同一程序中的多個執行緒共享該程序的