Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EXC_BAD_ACCESS when using SQLite (FMDB) and threads on iOS 4.0

I am using FMDB to deal with my database which works fine. The app uses a background thread which is doing some work and needs to access the database. At the same time the main thread needs to run some queries on the same database. FMDB itself has a little locking system, however, I added another to my classes.

Every query is only performed if my class indicates that the database is not in use. After performing the actions the database gets unlocked. This works as expected as long as the load is not too high. When I access a lot of data with the thread running on the main thread an EXC_BAD_ACCESS error occurs.

Here is the looking:

- (BOOL)isDatabaseLocked {
    return isDatabaseLocked;
}

- (Pile *)lockDatabase {
    isDatabaseLocked = YES;
    return self;        
}

- (FMDatabase *)lockedDatabase {
    @synchronized(self) {
        while ([self isDatabaseLocked]) {
            usleep(20);
            //NSLog(@"Waiting until database gets unlocked...");
        }
        isDatabaseLocked = YES;
        return self.database;       
    }
}

- (Pile *)unlockDatabase {
    isDatabaseLocked = NO;
    return self;            
}

The debugger says that the error occurs at [FMResultSet next] at the line

rc = sqlite3_step(statement.statement);

I double checked all retain counts and all objects do exist at this time. Again, it only occurs when the main thread starts a lot of queries while the background thread is running (which itself always produce heavy load). The error is always produced by the main thread, never by the background thread.

My last idea would be that both threads run lockedDatabase at the same time so they could get a database object. That's why I added the mutex locking via "@synchronized(self)". However, this did not help.

Does anybody have a clue?

like image 364
danielkbx Avatar asked Jun 29 '10 21:06

danielkbx


1 Answers

SQLite provides a much simpler serialization. By just setting the sqlite_config() option SQLITE_CONFIG_SERIALIZED you will probably avoid most of these kinds of headaches. I discovered this the hard way after fighting with threading issues for a long while.

Here's how you use it, you can put it in the init method of FMDatabase...

    if (sqlite3_config(SQLITE_CONFIG_SERIALIZED) == SQLITE_ERROR) {
        NSLog(@"couldn't set serialized mode");
    }

See the SQLite docs on threadsafety and serialized mode for more info.

like image 175
Rik Smith-Unna Avatar answered Nov 02 '22 18:11

Rik Smith-Unna