Objective C我应该怎样做才能使这些函数线程安全?

时间:2014-05-04 17:18:46

标签: objective-c multithreading sqlite thread-safety

情况就是这样。 我有一个单例类调用DBManager与sqlite3。插入,删除,选择都是通过这个类完成的。 假设现在ClassA需要向表a插入一条记录,而ClassB需要从表a中选择一条记录。所以presudo代码是这样的。

Class A
[[DBManager getInstance] insertRecord:@"12345"];

Class B
-(void)processData{
    Record r = [[DBManager getInstance] getRecord];
    // working with record r. after that doing some layout update
    [self.lbTitle setText:r.name];
}

因为在我的项目中,有4-5个类会访问db。所以有时数据库被锁定错误就是抛出而我的应用程序崩溃了。 我知道其中一个解决方案是使用GCD dispatch_async(CUSTOM_DB_QUEUE,block) 使用这些块来处理与db相关的所有代码。 但如果是这样,我还需要像这样修改B类。我是对的吗?

Class B
-(void)processData{
   dispatch_async(CUSTOM_DB_QUEUE,{
   [[DBManager getInstance] getRecord onRecordGot:^(Record* r) {
       // working with record r. after that doing some layout update
       dispatch_async(MAIN_QUEUE,{
       [self.lbTitle setText:r.name];
       )};
    }];
)};
} 

这种做法是否正确?所以我需要在DBManager中更改所有代码以使用块编码返回结果? 是否有任何简单的方法来排队保持DBManager类??

2 个答案:

答案 0 :(得分:1)

有一种更好的方法。不要对调用DBManager的代码进行任何更改。所有更改都应在DBManager课程内进行。并且没有理由使用dispatch_async。使用dispatch_sync

此代码保持不变:

Class A
[[DBManager getInstance] insertRecord:@"12345"];

Class B
-(void)processData{
    Record r = [[DBManager getInstance] getRecord];
    // working with record r. after that doing some layout update
    [self.lbTitle setText:r.name];
}

insertRecord:方法中,您可以将其更改为:

- (void)insertRecord:(NSString *)record {
    dispatch__barrier_sync(CUSTOM_DB_QUEUE, ^{
        // original code to insert record
    };
}

您的getRecord方法变为:

- (Record *)getRecord {
    __block Record *result = nil;

    dispatch_sync(CUSTOM_DB_QUEUE, ^{
        // original code that sets result
    };

    return result;
}

通过使用dispatch_syncdispatch_barrier_sync,此代码允许对getRecord进行任意数量的并发调用,但只允许调用insertRecord。它还可确保在getRecord运行时阻止对insertRecord:的呼叫。

答案 1 :(得分:0)

要使其线程安全,可以使用pthread_mutex_t作为全局实例。根据其用途锁定/解锁此互斥锁 e.g。

pthread_mutex_t *dbLock;

Class A
pthread_mutex_lock(dbLock);

[[DBManager getInstance] insertRecord:@"12345"];

pthread_mutex_unlock(dbLock);

Class B
-(void)processData{
    pthread_mutex_lock(dbLock);

    Record r = [[DBManager getInstance] getRecord];
    // working with record r. after that doing some layout update
    [self.lbTitle setText:r.name];

    pthread_mutex_unlock(dbLock);
}