概述
Sqlite3数据库互斥是基于文件的,即一个数据库文件中如果包含多张表T1、T2...Tn,当有进程对其中的表Tx进行写操作时,其余试图读写Tn的操作都会立即返回IS_LOCK,导致写数据库失败。因此,Sqlite3经常用于嵌入式开发中对并发要求不高的场景。
悲剧的是现有的系统用的是Sqlite3,但却要求较高的并发度。
于是一个选择被提上议程:更换数据库 or 修改现有sqlite3的行为?
长远来看,更换数据库方为解决之道,但目前来说修改现有sqlite3的行为投入较少,先解燃眉之急。
修订方案
将sqlite3_exec函数修订为阻塞和非阻塞两种方式。
技术选择
Sqlite3作为数据库,以文件的形式存在,供多进程访问,实现数据共享。操作Sqlite3的接口被编译成共享库的形式供多进程动态链接调用。要对sqlite3_exec函数实现互斥,必然需要新增互斥变量,不管使用信号量还是锁,都会遇到一个问题:互斥变量使用共享库的形式发布,各进程调用的时候会在自己的内存空间拷贝一个副本,导致各个进程无法实现互斥。解决这个问题有多种方法,这边记录有名信号量的使用。
实验程序
点击(此处)折叠或打开
- share.c:
- #include "share.h"
- sem_t *sem = NULL;
- void print_num()
- {
- int tmp;
- sem = sem_open("my_sem", O_RDWR);
- if (sem == NULL) {
- printf("Get sem failed.\n");
- return ;
- }
-
- printf("Open sem success.\n");
-
- sem_wait(sem);
- printf("Input the number, 0 for quit\n");
- while(1) {
- scanf("%d", &tmp);
- printf("The input is %d.\n", tmp);
- if (0 == tmp) {
- printf("Input 0, ending...\n");
- sem_post(sem);
- return ;
- }
- printf("================================================\n");
- }
- }
- void share_init()
- {
- /* 创建一个命名信号量 */
- sem = sem_open("my_sem", O_RDWR|O_CREAT, 0077, 1);
- if (sem == NULL) {
- printf("Create sem failed.\n");
- return ;
- }
- printf("Create sem success.\n");
- }
点击(此处)折叠或打开
- share.h:
- #include <semaphore.h>
- #include <stdio.h>
- #include <errno.h>
- #include <fcntl.h>
- extern void print_num();
- extern void share_init();
以上两个文件被编译成共享库:share.c:gcc -fPIC -shared -pthread -o share.so share.c
点击(此处)折叠或打开
- share_init.c:
- #include "share.h"
- void main()
- {
- share_init();
- printf("Init OK.\n");
- }
以上文件被编译成share_init程序,用于初始化信号量:share_init.c:gcc -o share_init share_init.c ./share.so
点击(此处)折叠或打开
- test.c:
- #include "share.h"
- void main()
- {
- sem_t *sem_tmp = NULL;
- sem_tmp = sem_open("my_sem", O_RDWR, 0077, 1);
- if (sem_tmp == NULL) {
- printf("Get sem failed.\n");
- return ;
- }
- print_num();
- }