fmdbqueue dealock可能的一個原因

症狀表現:

    總是crash ,後臺打印:

     inDatabase: was called reentrantly on the same queue, which would lead to a deadlock

    錯誤代碼如下:


     

  //use fmdb larger bugs ,不能在執行一個fmdbqueue還沒有執行完畢的時候,去執行另外一個fmdbqueue


    [[SQLUtils getInstance]saveRulesAction:rulesArray rulesDescription:ruleDescription result:^(BOOL sucess) {


      [[SQLUtils getInstance]updateRules];

        if(done){

            done(sucess);

            //the rule has changed we should check it now

            if(sucess){

                dispatch_async(dispatch_get_main_queue(), ^{

                    [self checkRules];

                });

            }

        }

    }];


-(void)saveRulesAction:(NSArray*)rules rulesInfo:(NSArray*)ruleInfo rulesDescription:(NSArray*)rulesDescription result:(void(^)(BOOL sucess))done

{

    [self checkDBQueue];

    __block BOOL is_exculate_success = NO;

    [queue inDatabase:^(FMDatabase *db) {

        [db beginTransaction];

        @try{


            for(int i=0;i<[ruleInfo count];i++){

                //delete the rules in db

                BOOL rc = [db executeUpdate:@"delete from rulesAction where ruleType=?",ruleInfo[i]];

                if(!rc){

                    debugLog(@"table rulesAction delete info error! info:%@",[db lastErrorMessage]);

                }

            }

            //ruleType actionType TEXT NOT NULL)"];

            //delete rules description info

            BOOL rc  = [db executeUpdate:@"delete from rulesDescription"];

            if(!rc){

                debugLog(@"table rulesDescription delete info error! info:%@",[db lastErrorMessage]);

            }

            

            if(rulesDescription!=nil){

                //save rules description info

                rc= [db executeUpdate:@"insert into rulesDescription(uuid,displayName,description) values (?,?,?)",rulesDescription[0],rulesDescription[1],rulesDescription[2]];

            }else{

                // rules description is nill

                //debugLog(@"rules description is nil");

            }


            //save all rules and action

            for (int i =0; i<[rules count]; i++) {

                NSArray * rule = rules[i];

                BOOL rc = [db executeUpdate:@"insert into rulesAction(ruleType,actionType,time,actionIndex,ruleLevel,hasDone,rulesKey,ruleTime) values (?,?,?,?,?,?,?,datetime('now'))",rule[0],rule[1],rule[2],rule[3],rule[4],rule[5],rule[6]];

                if(!rc){

                    debugLog(@"saveRulesAction into db failed!  db error info is %@",[currentDB lastErrorMessage]);

                }

            }

            if (done)

      {

           done(YES);

      }

    

        }

        @catch (NSException *exception) {

            [db rollback];

            debugLog( @"Failed to open database file with message %@ in saveRulesAction", [db lastErrorMessage]);

           

        if (done)

      {

           done(NO);

      }

            

        }

        @finally {

            [db commit];

        }

    }];

}

正確代碼:

     

-(void)saveRulesAction:(NSArray*)rules rulesInfo:(NSArray*)ruleInfo rulesDescription:(NSArray*)rulesDescription result:(void(^)(BOOL sucess))done

{

    [self checkDBQueue];

    __block BOOL is_exculate_success = NO;

    [queue inDatabase:^(FMDatabase *db) {


        [db beginTransaction];

        @try{


            for(int i=0;i<[ruleInfo count];i++){

                //delete the rules in db

                BOOL rc = [db executeUpdate:@"delete from rulesAction where ruleType=?",ruleInfo[i]];

                if(!rc){

                    debugLog(@"table rulesAction delete info error! info:%@",[db lastErrorMessage]);

                }

            }

            //ruleType actionType TEXT NOT NULL)"];

            //delete rules description info

            BOOL rc  = [db executeUpdate:@"delete from rulesDescription"];

            if(!rc){

                debugLog(@"table rulesDescription delete info error! info:%@",[db lastErrorMessage]);

            }

            

            if(rulesDescription!=nil){

                //save rules description info

                rc= [db executeUpdate:@"insert into rulesDescription(uuid,displayName,description) values (?,?,?)",rulesDescription[0],rulesDescription[1],rulesDescription[2]];

            }else{

                // rules description is nill

                //debugLog(@"rules description is nil");

            }


            //save all rules and action

            for (int i =0; i<[rules count]; i++) {

                NSArray * rule = rules[i];

                BOOL rc = [db executeUpdate:@"insert into rulesAction(ruleType,actionType,time,actionIndex,ruleLevel,hasDone,rulesKey,ruleTime) values (?,?,?,?,?,?,?,datetime('now'))",rule[0],rule[1],rule[2],rule[3],rule[4],rule[5],rule[6]];

                if(!rc){

                    debugLog(@"saveRulesAction into db failed!  db error info is %@",[currentDB lastErrorMessage]);

                }

            }

            

            is_exculate_success = YES;

        }

        @catch (NSException *exception) {

            [db rollback];

            debugLog( @"Failed to open database file with message %@ in saveRulesAction", [db lastErrorMessage]);

            is_exculate_success = NO;

            

        }

        @finally {

            [db commit];

        }

    }];

    if(done){

        done(is_exculate_success);

    }

}

  問題說明:一個queue的block還沒有執行完,就在done  block塊中執行了,另外的queue查詢;導致程序中出現了兩個queue;

  解決過程:

     根據報錯情況調查: 

    

- (void)inDatabase:(void (^)(FMDatabase *db))block {

    /* Get the currently executing queue (which should probably be nil, but in theory could be another DB queue

     * and then check it against self to make sure we're not about to deadlock. */

    FMDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey);

    assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock");

    

    FMDBRetain(self);

   

    dispatch_sync(_queue, ^() {

        NSLog(@"dispatch_sync queue start");

        FMDatabase *db = [self database];

        block(db);

        

        if ([db hasOpenResultSets]) {

            NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]");

            

#if defined(DEBUG) && DEBUG

            NSSet *openSetCopy = FMDBReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]);

            for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) {

                FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue];

                NSLog(@"query: '%@'", [rs query]);

            }

#endif

        }

        NSLog(@"dispatch_sync queue end");

    });

    

    FMDBRelease(self);

}

   上述代碼中居然沒有執行這個NSLog(@"dispatch_sync queue end");,就出現了死鎖,說明上一個indatabase:還沒有執行完畢,另外一個就又開始了,根據程序的執行順序一一排查,block塊外的queue還沒有執行完畢,就開是了另外一個indatabase的調用,可見上述代碼的問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章