sqlite3 读写锁
转载:https://blog.csdn.net/u012218838/article/details/79362929(sqlite3 使用读写锁SRWLOCK例子)
转载:https://my.oschina.net/u/1426828/blog/1793762(SRWLock介绍使用)
转载:https://www.cnblogs.com/5iedu/p/4727734.html(SRWLock使用demo)
转载:https://docs.microsoft.com/zh-cn/windows/desktop/api/synchapi/nf-synchapi-acquiresrwlockexclusive(SRWLock官方文档)
转载:https://blog.csdn.net/MoreWindows/article/details/7650574
读写锁在对资源进行保护的同时,还能区分想要读取资源值的线程(读取者线程)和想要更新资源的线程(写入者线程)。对于读取者线程,读写锁会允许他们并发的执行。当有写入者线程在占有资源时,读写锁会让其它写入者线程和读取者线程等待。因此用读写锁来解决读者写者问题会使代码非常清晰和简洁。
SRWLock
从visual studio2005开始你可以使用SRWLock,和CRITICAL_SECTION(关键段)差不过的功能,不同的是由程序员控制读写线程,如果是读线程,可以同时读取,如果是写线程,则其他线程挂起,写完后马上就可以读取
首先,需要一个SRWLOCK结构,然后调用InitializeSRWLock(PSWRLOCK srwLock)函数初始化这个结构。
SRWLOCK srw; InitializeSRWLock(&srw);
一旦初始化完成,就可以对写入线程调用AcquireSRWLockExclusive()函数和ReleaseSRWLockExclusive()函数 AcquireSRWLockExclusive(&srw);
//...写入数据,写入东西的时候该线程独占,其他任何线程不可进入 ReleaseSRWLockExclusive(&srw); 对于只读线程可以调用AcquireSRWLockShared()函数和ReleaseSRWLockShared()函数,如下 AcquireSRWLockShared(&srw); //..读取数据,如果这时没有写入数据则多个读取线程可以进行
ReleaseSRWLockShared)&srw);
读/写锁
SRWLock的目的和关键段相同:对一个资源进行保护,不让其它线程访问它。但是,与关键段不同的是,SRWLock允许我们区分哪些想要读取资源的值的线程(读取者线程)和想要更新资源的值的线程(写入者线程)。让所有的读取者线程在同一时刻访问共享资源应该是可行的,这是因为仅仅读取资源的值并不存在破坏数据的风险。只有当写入者线程想要对资源进行更新的时候才需要进行同步。在这种情况下,写入者线程想要对资源进行更新的时候才需要进行同步。在这种情况下,写入者线程应该独占对资源的访问权:任何其它线程,无论是读取者线程还是写入者线程,都不允许访问资源。这就是SRWLock提供的全部功能。
首先,我们需要分配一个SRWLOCK结构并用InitializeSRWLock函数对它进行初始化:
void InitializeSRWLock(PSRWLOCK SRWLock);
一旦SRWLock初始化完成之后,写入者线程就可以调用AcquireSRWLockExclusive,将SRWLOCK对象的地址作为参数传入,以尝试获得对被保护资源的独占访问权。
void AcquireSRWLockExclusive(PSRWLOCK SRWLock);
完成对资源的更新之后,应该调用ReleaseSRWLockExclusice,并将SRWLOCK对象的地址作为参数传入,这样就解除了对资源的锁定。
void ReleaseSRWLockExclusive(PSRWLOCK SRWLock);
对读取者线程来说,同样有两个步骤,单调用的是下面两个新的函数:
void AcquireSRWLockShared(PSRWLOCK SRWLock); void ReleaseSRWLockShared(PSRWLOCK SRWLock);
SRWLock锁的共享规则:
①若当前锁的状态是“写”(即某个线程已经获得排它锁),这时其他线程,不管是申请读或写锁的线程,都会被阻塞在AcquireSRWLock*函数中。读锁或写锁等待计数加1。
②若当前锁的状态是“读”(即某个(些)线程已经获得了共享锁)。
A、如果新的线程申请写锁,则此时它将被挂起,锁的写等待计数加1。直至当前正在读锁的线程全部结束,然后系统会唤醒正在等待写的线程,即申请排他锁要在没有任何其他锁的时候才能返回。
B、如果新的线程申请读锁,若此时没有写线程正在等待,则允许读锁进入而不会被阻塞。如果有写锁正在等待,则写锁优先得到锁,新线程进入等待,读锁计数加1(这样做的目的是让写锁有机会进入)。
不存在用来删除或销毁SRWLOCK的函数,系统会自动执行清理工作。
与关键段相比,SRWLock缺乏下面两个特性:
1)不存在TryEnter(Shared/Exclusive)SRWLock 之类的函数:如果锁已经被占用,那么调用AcquireSRWLock(Shared/Exclusive) 会阻塞调用线程。
2)不能递归地调用SRWLOCK。也就是说,一个线程不能为了多次写入资源而多次锁定资源,然后再多次调用ReleaseSRWLock* 来释放对资源的锁定。
总结,如果希望在应用程序中得到最佳性能,那么首先应该尝试不要共享数据,然后依次使用volatile读取,volatile写入,Interlocked API,SRWLock以及关键段。当且仅当所有这些都不能满足要求的时候,再使用内核对象。因为每次等待和释放内核对象都需要在用户模式和内核模式之间切换,这种切换的CPU开销非常大。
具体参考代码:
//读者与写者问题继 读写锁SRWLock
#include <stdio.h>
#include <process.h>
#include <windows.h>
//设置控制台输出颜色
BOOL SetConsoleColor(WORD wAttributes)
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if (hConsole == INVALID_HANDLE_VALUE)
return FALSE;
return SetConsoleTextAttribute(hConsole, wAttributes);
}
const int READER_NUM = ; //读者个数
//关键段和事件
CRITICAL_SECTION g_cs;
SRWLOCK g_srwLock;
//读者线程输出函数(变参函数的实现)
void ReaderPrintf(char *pszFormat, ...)
{
va_list pArgList;
va_start(pArgList, pszFormat);
EnterCriticalSection(&g_cs);
vfprintf(stdout, pszFormat, pArgList);
LeaveCriticalSection(&g_cs);
va_end(pArgList);
}
//读者线程函数
unsigned int __stdcall ReaderThreadFun(PVOID pM)
{
ReaderPrintf(" 编号为%d的读者进入等待中...n", GetCurrentThreadId());
//读者申请读取文件
AcquireSRWLockShared(&g_srwLock);
//读取文件
ReaderPrintf("编号为%d的读者开始读取文件...n", GetCurrentThreadId());
Sleep(rand() % );
ReaderPrintf(" 编号为%d的读者结束读取文件n", GetCurrentThreadId());
//读者结束读取文件
ReleaseSRWLockShared(&g_srwLock);
return ;
}
//写者线程输出函数
void WriterPrintf(char *pszStr)
{
EnterCriticalSection(&g_cs);
SetConsoleColor(FOREGROUND_GREEN);
printf(" %sn", pszStr);
SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
LeaveCriticalSection(&g_cs);
}
//写者线程函数
unsigned int __stdcall WriterThreadFun(PVOID pM)
{
WriterPrintf("写者线程进入等待中...");
//写者申请写文件
AcquireSRWLockExclusive(&g_srwLock);
//写文件
WriterPrintf(" 写者开始写文件.....");
Sleep(rand() % );
WriterPrintf(" 写者结束写文件");
//标记写者结束写文件
ReleaseSRWLockExclusive(&g_srwLock);
return ;
}
int main()
{
printf(" 读者写者问题继 读写锁SRWLockn");
printf(" ----nn");
//初始化读写锁和关键段
InitializeCriticalSection(&g_cs);
InitializeSRWLock(&g_srwLock);
HANDLE hThread[READER_NUM + ];
int i;
//先启动二个读者线程
for (i = ; i <= ; i++)
hThread[i] = (HANDLE)_beginthreadex(NULL, , ReaderThreadFun, NULL, , NULL);
//启动写者线程
hThread[] = (HANDLE)_beginthreadex(NULL, , WriterThreadFun, NULL, , NULL);
Sleep();
//最后启动其它读者结程
for ( ; i <= READER_NUM; i++)
hThread[i] = (HANDLE)_beginthreadex(NULL, , ReaderThreadFun, NULL, , NULL);
WaitForMultipleObjects(READER_NUM + , hThread, TRUE, INFINITE);
for (i = ; i < READER_NUM + ; i++)
CloseHandle(hThread[i]);
//销毁关键段
DeleteCriticalSection(&g_cs);
return ;
}
sqlite 写线程
unsigned WINAPI WriteThreads(void *pPM)
{
while()
{
Sleep();
AcquireSRWLockExclusive(&srwLock);
printf("写线程\n");
char chsql[] = {};
sprintf(chsql,"insert into tab1 values ('thread 0X%08X write 1')",GetCurrentThreadId()); int nret = sqlite3_exec(m_db,chsql,NULL,NULL,NULL);
if(nret != SQLITE_OK)
{
printf("================write error============\n");
}
ReleaseSRWLockExclusive(&srwLock);
} return ; }
读线程
unsigned WINAPI ReadThreads(void *pPM)
{
while()
{
Sleep();
AcquireSRWLockShared(&srwLock);
printf("读线程\n");
char chsql[] = {};
sprintf(chsql,"select id from tab1 "); int nret = sqlite3_exec(m_db,chsql,NULL,NULL,NULL);
if(nret != SQLITE_OK)
{
printf("================read error============\n");
}
ReleaseSRWLockShared(&srwLock);
} return ; }
sqlite3 读写锁的更多相关文章
- 技术笔记:Delphi多线程应用读写锁
在多线程应用中锁是一个很简单又很复杂的技术,之所以要用到锁是因为在多进程/线程环境下,一段代码可能会被同时访问到,如果这段代码涉及到了共享资源(数据)就需要保证数据的正确性.也就是所谓的线程安全.之前 ...
- java多线程-读写锁
Java5 在 java.util.concurrent 包中已经包含了读写锁.尽管如此,我们还是应该了解其实现背后的原理. 读/写锁的 Java 实现(Read / Write Lock Java ...
- 让C#轻松实现读写锁分离
ReaderWriterLockSlim 类 表示用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问. 使用 ReaderWriterLockSlim 来保护由多个线程读取但每次只采用一 ...
- C#读写锁ReaderWriterLockSlim的使用
读写锁的概念很简单,允许多个线程同时获取读锁,但同一时间只允许一个线程获得写锁,因此也称作共享-独占锁.在C#中,推荐使用ReaderWriterLockSlim类来完成读写锁的功能. 某些场合下,对 ...
- 可重入锁 公平锁 读写锁、CLH队列、CLH队列锁、自旋锁、排队自旋锁、MCS锁、CLH锁
1.可重入锁 如果锁具备可重入性,则称作为可重入锁. ========================================== (转)可重入和不可重入 2011-10-04 21:38 这 ...
- 用读写锁三句代码解决多线程并发写入文件 z
C#使用读写锁三句代码简单解决多线程并发写入文件时提示“文件正在由另一进程使用,因此该进程无法访问此文件”的问题 在开发程序的过程中,难免少不了写入错误日志这个关键功能.实现这个功能,可以选择使用第三 ...
- 锁的封装 读写锁、lock
最近由于项目上面建议使用读写锁,而去除常见的lock锁.然后就按照需求封装了下锁.以简化锁的使用.但是开发C#的童鞋都知道lock关键字用起太方便了,但是lock关键字不支持超时处理.很无奈,为了实现 ...
- Java多线程13:读写锁和两种同步方式的对比
读写锁ReentrantReadWriteLock概述 大型网站中很重要的一块内容就是数据的读写,ReentrantLock虽然具有完全互斥排他的效果(即同一时间只有一个线程正在执行lock后面的任务 ...
- 让C#轻松实现读写锁分离--封装ReaderWriterLockSlim
ReaderWriterLockSlim 类 表示用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问. 使用 ReaderWriterLockSlim 来保护由多个线程读取但每次只采用一 ...
随机推荐
- selenium获取元素
1.获取窗口titledriver.title2.获取urldriver.current_url3.获取窗口截图driver.get_screenshot_as_file('window.png')4 ...
- 05-jQuery介绍
本篇主要介绍jQuery的加载.jquery选择器.jquery的样式操作.jQuery的事件.jquery动画等相关知识. 一.jQuery介绍 jQuery是目前使用最广泛的javascript函 ...
- Python的正则表达式re模块
Python的正则表达式(re模块) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Python使用re模块提供了正则表达式处理的能力.如果对正则表达式忘记的一干二净的话,可以花费 ...
- php数组打乱顺序
shuffle() PHP shuffle() 函数随机排列数组单元的顺序(将数组打乱).本函数为数组中的单元赋予新的键名,这将删除原有的键名而不仅是重新排序. 语法: bool shuffle ( ...
- 10、Hadoop组件启动方式和SSH无密码登陆
启动方式 一.各个组件逐一启动 hdfs: hadoop-daemon.sh start|stop namenode|datanode|secondnode yarn: yarn-demon.sh s ...
- Combined beamformers for robust broadband regularized superdirective beamforming
[未完待续]结合波束形成器的鲁棒性宽带正则化超指向波束形成方法[1].用于宽带信号的波束形成方法.结合延时求和波束形成DSB以及超指向波束形成SDB方法,给定用户自定义的正则化因子,采用一个简单的参数 ...
- 点击复制文字到剪贴板兼容性安卓ios
一般那种活动H5分享可能会用到点击复制文字到剪贴板,很简单的功能 于是搜了一搜:js复制文字到剪贴板,可用结果大致分为两类: 一类是js原生方法,这种方法兼容性不好,不兼容ios: https://d ...
- Mac下删除自己安装的Python
删除Python框架sudo rm -rf /Library/Frameworks/Python.framework/Versions/x.x 删除Python程序sudo rm -rf “/Appl ...
- Zotero使用教程(2)-数据备份
小书匠 这篇文章的目标是让你无论是 换系统,重新安装zotero等都可以还原回你的文献库,而且整个过程基本是自动完成的. 这部分解决下面的两种情况: 1.zotero有自己既定的一套存储方式,不是一般 ...
- 洛谷P2432 zxbsmk爱查错
题目 DP,需要注意边界上的问题. 状态定义\(dp[i]\)为句子第i位去除字母的最小值,答案就是\(dp[len]\). 易得状态转移方程为: \[dp[i]=min(dp[i-1]+1,dp[l ...