转载: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 读写锁的更多相关文章

  1. 技术笔记:Delphi多线程应用读写锁

    在多线程应用中锁是一个很简单又很复杂的技术,之所以要用到锁是因为在多进程/线程环境下,一段代码可能会被同时访问到,如果这段代码涉及到了共享资源(数据)就需要保证数据的正确性.也就是所谓的线程安全.之前 ...

  2. java多线程-读写锁

    Java5 在 java.util.concurrent 包中已经包含了读写锁.尽管如此,我们还是应该了解其实现背后的原理. 读/写锁的 Java 实现(Read / Write Lock Java ...

  3. 让C#轻松实现读写锁分离

    ReaderWriterLockSlim 类 表示用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问. 使用 ReaderWriterLockSlim 来保护由多个线程读取但每次只采用一 ...

  4. C#读写锁ReaderWriterLockSlim的使用

    读写锁的概念很简单,允许多个线程同时获取读锁,但同一时间只允许一个线程获得写锁,因此也称作共享-独占锁.在C#中,推荐使用ReaderWriterLockSlim类来完成读写锁的功能. 某些场合下,对 ...

  5. 可重入锁 公平锁 读写锁、CLH队列、CLH队列锁、自旋锁、排队自旋锁、MCS锁、CLH锁

    1.可重入锁 如果锁具备可重入性,则称作为可重入锁. ========================================== (转)可重入和不可重入 2011-10-04 21:38 这 ...

  6. 用读写锁三句代码解决多线程并发写入文件 z

    C#使用读写锁三句代码简单解决多线程并发写入文件时提示“文件正在由另一进程使用,因此该进程无法访问此文件”的问题 在开发程序的过程中,难免少不了写入错误日志这个关键功能.实现这个功能,可以选择使用第三 ...

  7. 锁的封装 读写锁、lock

    最近由于项目上面建议使用读写锁,而去除常见的lock锁.然后就按照需求封装了下锁.以简化锁的使用.但是开发C#的童鞋都知道lock关键字用起太方便了,但是lock关键字不支持超时处理.很无奈,为了实现 ...

  8. Java多线程13:读写锁和两种同步方式的对比

    读写锁ReentrantReadWriteLock概述 大型网站中很重要的一块内容就是数据的读写,ReentrantLock虽然具有完全互斥排他的效果(即同一时间只有一个线程正在执行lock后面的任务 ...

  9. 让C#轻松实现读写锁分离--封装ReaderWriterLockSlim

    ReaderWriterLockSlim 类 表示用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问. 使用 ReaderWriterLockSlim 来保护由多个线程读取但每次只采用一 ...

随机推荐

  1. python系列:一、Urllib库的基本使用

    开篇介绍: 因为我本人也是初学者,爬虫的例子大部分都是学习资料上面来的,只是自己手敲了一遍,同时加上自己的理解. 写得不好请多谅解,如果有错误之处请多赐教. 我本人的开发环境是vscode,pytho ...

  2. 爬虫之scrapy框架应用selenium

    一.利用selenium 爬取 网易军事新闻 使用流程: ''' 在scrapy中使用selenium的编码流程: 1.在spider的构造方法中创建一个浏览器对象(作为当前spider的一个属性) ...

  3. CVE-2019-0708:RDP终极EXP复现

    0x00 前言 每次复现都会遇到各种各样的问题,这次也不例外,经过多次尝试才复现成功,因此把可能的解决方法也和大家分享一下,有想要一起复现学习/投稿的可以联系我哈 0x01 影响版本 Windows ...

  4. axure快速上手

    Axure RP是一个专业的快速原型设计工具.Axure(发音:Ack-sure),代表美国Axure公司:RP则是Rapid Prototyping(快速原型)的缩写.Axure RP是美国Axur ...

  5. Spring源码窥探之:扩展原理BeanDefinitionRegistryPostProcessor

    BeanDefinitionRegistryPostProcessor继承自BeanFactoryPostProcessor,其中有两个接口,postProcessBeanDefinitionRegi ...

  6. Open Source Isn't A Business Model, It's A Market Strategy

    https://www.forbes.com/sites/quora/2017/09/29/open-source-isnt-a-business-model-its-a-market-strateg ...

  7. (生鲜项目)05. RESTful api, 和 VUE

    第一步: 什么是 RESTful api 总结: 使用http协议作为介质, 达到客户端修改服务器端资源的目的, 服务器只需要提供指定的api接口, 客户端根据http协议中的post/get/put ...

  8. 斜率优化板题 HDU2829 Lawrence

    题目大意:给定一个长度为nnn的序列,至多将序列分成m+1m+1m+1段,每段序列都有权值,权值为序列内两个数两两相乘之和.求序列权值和最小为多少? 数据规模:m<=n<=1000.m&l ...

  9. HTML 009 select_jquery操作下拉框select

    取值问题 <select id="selector"> <option value="1">选项一</option> < ...

  10. HTML事件(onclick、onmouseover、onmouseout、this)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...