sqlite3.dylib: illegal multi-threaded access to database connection

It turns out that SQLITE_CONFIG_MULTITHREAD mode works well on a multi-threading environment as long as you don't use the same connection simultaneously; which happen to be the exact scenario that I had. Therefore, to solve this issue you can either open a new connection for each thread or use SQLITE_CONFIG_SERIALIZED in full mutex mode using SQLITE_OPEN_FULLMUTEX flag to open the connection.

The helper method ended up like so:

+(sqlite3*) getInstance {
  if (instance == NULL) {
    sqlite3_shutdown();
    sqlite3_config(SQLITE_CONFIG_SERIALIZED);
    sqlite3_initialize();

    NSLog(@"isThreadSafe %d", sqlite3_threadsafe());

    const char *path = [@"./path/to/db/db.sqlite" cStringUsingEncoding:NSUTF8StringEncoding];

    if (sqlite3_open_v2(path, &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_FULLMUTEX, NULL) != SQLITE_OK) {
      NSLog(@"Database opening failed!");
    }
  }

  return instance;
}

Use please SQLite Shared-Cache Mode https://www.sqlite.org/sharedcache.html

sqlite3_open_v2(path.path, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE, nil) != SQLITE_OK

SQLITE_OPEN_SHAREDCACHE

Reliable 100% :)


In case of any one faced this problem in Swift. Solution will be:

let dbName = "first.db"
static let shared = DatabaseManger()
var db: OpaquePointer?


private init(){
    print("singletone initialized")
    sqlite3_shutdown();
    let dbPath = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
        .appendingPathComponent(dbName)
    if sqlite3_open_v2(dbPath.path, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX, nil) == SQLITE_OK {
        print("Successfully opened database connection at \(dbPath.path)")
    }
    else {
        print("unable to open database connection")
    }
}

This code tested in swift version 4.0 and 4.2

Tags:

Sqlite

Ios