【原创】sqlite线程安全实验【chad20130201】

【原创】sqlite线程安全实验【chad20130201】

编译sqlite时使用默认配置,启用了线程安全设置。

实验程序如下:

int Query_db( char* db_file_name )
{
    printf("in %s\n",__FUNCTION__);
    int    ret;
    sqlite3_stmt    *pstmt = NULL;
    char    *errMsg = NULL;
    char    *sql = "SELECT * FROM MonthFreezeTable WHERE id<500;";//查询表中有多少列
    int    id;
    STRUCT_TEST1    test_struct1;
    STRUCT_TEST2    test_struct2;

    memset(&test_struct1,0,sizeof(test_struct1));
    memset(&test_struct2,0,sizeof(test_struct2));

    ret = sqlite3_prepare(pdb, sql, strlen(sql), &pstmt, &errMsg);
     if( ret != SQLITE_OK )
    {
        printf("error code :%d,reason:%s\n",ret,errMsg);
        sqlite3_free( errMsg );
        return -1;
    }/*这一部分程序有问题*/
    while( 1 )
    {
        ret = sqlite3_step(pstmt);
        if( ret != SQLITE_ROW )
        {    break; }
        id = sqlite3_column_int(pstmt, 0);
        printf("id = %d ",id);
        usleep(10000);
    }
    sqlite3_finalize( pstmt ); //把刚才分配的内容析构掉
    sqlite3_reset( pstmt );

    return 0;

}
int    UpdateBlobData(char *db_file_name)
{
    printf("in %s\n",__FUNCTION__);
    int    ret;
    sqlite3_stmt    *pstmt = NULL;
    char    *errMsg = NULL;
    char    sql[1023];// = "UPDATE MonthFreezeTable SET TimeScale=datetime(),ForwardPowerInd=:forw WHERE id>0;";
    int        index1,index2;
    char    *timebuf="2010-11-11";
    clock_t starttime, endtime;
    double totaltime;
    starttime = clock();

    printf("start update the db \n");
    int i ;
    for(i=0;i<441;i++){
        printf("%10d",i);
        //timebuf = Now();
        //printf("Now:%s",timebuf);
        sprintf(sql,"UPDATE MonthFreezeTable SET TimeScale=datetime(),ForwardPowerInd=:forw WHERE id=%d;",i);
        ret = sqlite3_prepare(pdb, sql,strlen(sql), &pstmt, &errMsg);//预编译
        if( ret != SQLITE_OK )
        {
            printf("error code :%d,reason:%s\n",ret,errMsg);
            sqlite3_free( errMsg );
            return -1;
        }
        index2 = sqlite3_bind_parameter_index( pstmt,":forw" );//生成索引 
        ret = sqlite3_bind_blob(pstmt, index2, 0, 10, SQLITE_STATIC);//绑定数据流 
        if( ret != SQLITE_OK )
        {
            printf("the sqlite3_bind_blob error!\n");
            printf("error code :%d \n",ret);
            return -1;
        }
    restep:
        sqlite3_busy_timeout(pdb, 1000);
        ret = sqlite3_step(pstmt);//执行
        if( ret != SQLITE_DONE )
        {
            if( ret == SQLITE_BUSY ){//SQLITE_BUSY
                printf("step timeout!\n");
                goto restep;
            }
            printf("the sqlite3_step error!\n");
            printf("error code :%d \n",ret);
            return -1;
        }
    }
    printf("end update the db \n");
    endtime = clock();
    totaltime = (double)( (endtime - starttime)/(double)CLOCKS_PER_SEC );
    printf("the total time = %f s\n",totaltime);
    printf("the step time = %f ms\n",(totaltime*1000)/(12*2041));

    sqlite3_finalize( pstmt ); //把刚才分配的内容析构掉
    sqlite3_reset( pstmt );

    return 0;
}

实验1:两个线程(进程同时进行数据查询操作!)

int main(void)
{
    int ret;

    ret = Create_db( "/home/terminal.db" );
    if(ret < 0)
    {
        return -1;
    }
    int pid = fork();
    if(pid < 0) {
        perror("fork error!\n");
        return 0;
    }
    if(pid==0){
        printf("the child pross!\n");
        ret = Query_db( "/home/terminal.db" );
        if(ret < 0)
        {
            return -1;
        }
        printf("child sleep 5!\n");
        sleep(5);
    }else{
        printf("the father pross!\n");
        ret = Query_db( "/home/terminal.db" );
        if(ret < 0)
        {
            return -1;
        }
        sleep(5);
        printf("father sleep 5!\n");
    }

    sqlite3_close(pdb);

    return 0;
}

打印结果如下所示:(示例)
这里写图片描述
如上图红色部分所示,两个进程分别交叉打印查询结果,这说明:sqlite3多线程查询互不影响,是线程安全的。
实验2:一个进程进行查询,一个进程进行更新操作,代码片段如下:

int pid = fork();
    if(pid < 0) {
        perror("fork error!\n");
        return 0;
    }
    if(pid==0){
        printf("the child pross!\n");
        ret = UpdateBlobData( "/home/terminal.db" );
        if(ret < 0)
        {
            return -1;
        }
        printf("child sleep 5!\n");
        sleep(5);
    }else{
        printf("the father pross!\n");
        ret = Query_db( "/home/terminal.db" );
        if(ret < 0)
        {
            return -1;
        }
        sleep(5);
        printf("father sleep 5!\n");
    }

执行结果如下:
这里写图片描述
结果如上,程序先运行了父进程,但是父进程的sqlite3_step(pstmt)返回了超时,同时,子进程的查询操作正确执行。待子进程查询完毕退出后父进程的更新操作才继续进行。这说明:sqlite的线程安全是有效的,当有数据更新操作时,更新操作是安全的互斥的,所以,编程时不需要专门编写线程锁程序对数据库操作进行保护。

由于SQLite仅仅提供了粒度很粗的数据锁,如读写锁,因此在每次加锁操作中都会有大量的数据被锁住,即使仅有极小部分的数据会被访问。换句话说,我们可以认为SQLite只是提供了表级锁,没有提供行级锁。在这种同步机制下,并发性能很难高效。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值