读写问题
假设某个数据对象是释若干进程共享的,这些进程的某些只会读这种共享对象的内容,另一些则只会更新这种共享对象数据。
可以把这些进程分为两类,一类负责读取数据对象,称为读者进程,另一类负责更新共享数据,称为写者进程。多个读者可以同时获取共享对象,但是当一个写者和另外一个读者(或者写者)同时存取对象时,就会发生混乱。
为了避免发生混乱现象,要求写者进程互斥地存取共享对象,这类同步问题就称为读写问题。
读写锁
读写锁是计算机程序的并发控制的一种同步机制,也称“共享-互斥锁”、多读者-单写者锁,它是一种特殊的自旋锁。
读写锁是用于解决类读写问题,比如有些公共数据修改的机会很少,但其读的机会很多。并且在读的过程中会伴随着查找,给这种代码加锁会降低我们的程序效率,读写锁可以解决此类问题;其中读操作可并发重入,而写操作是互斥的。
优先级策略
根据不同的优先级策略,可以将读写锁分为以下两种:
- 读者优先:允许最大并发,但写操作可能饿死。
- 写者优先:一旦所有已经开始的读操作完成,等待的写操作立即获得锁。
读者优先策略:
除非有写者在写文件,否则没有一个读者需要等待。
分析思想:
读者到:
1)无读者、写者,新读者可以读
2)有写者等,但有其它读者正在读,则新读者也可以读
3)有写者写,新读者等
写者到:
1)无读者,新写者可以写
2)有读者,新写者等待
3)有其它写者,新写者等待
写者优先策略:
一旦一个写者到来,它应该尽快对文件进行写操作。则新来到的读者不允许进行读操作。
分析思想:
读者到:
1) 无读者且无写者,新读者读
2) 有读者但无写者等待,新读者读
3) 有读者但有写着等待,读者等待
4) 有写者在写,新读者等待
写者到:
1) 无读者且无写者,新写者写
2) 有读者在读,新写者等待
3) 有写者写,新写者等待
Windows系统读写锁
读写锁(Slim reader/writer,SRW lock)用于进程内的线程间同步。 SRW既不是公平的也不是先进先出的。SRW锁提供两种读取模式,访问共享资源 :
共享模式,它允许多个读取线程对共享资源进行只读访问,从而使它们能够同时从共享资源中读取数据。
独占模式,它授予对一个写入线程的一次读/写访问权限。在独占模式下获取锁定后,在写者线程释放锁定之前,其他任何线程都无法访问该共享资源。
相关API
实例:
int g_test_data = 0;
SRWLOCK g_srwLock;
const int MAX_RAND_TIME = 10;
const int MAX_RADN_DATA = 1000;
void reader(int id)
{
int rand_time = rand() % MAX_RAND_TIME;
//线程安全型打印
CStdPrinter::PrintMsg("reader thread(%d) read begin....\n", id);
std::this_thread::sleep_for(std::chrono::milliseconds(rand_time * 300));
CStdPrinter::PrintMsg("reader thread(%d) read end (data : %d)....\n", id, g_test_data);
}
void writer(int nID)
{
int rand_time = rand() % MAX_RAND_TIME;
CStdPrinter::PrintMsg("\t writer thread (%d) writer data begin....\n", nID);
g_test_data = (rand()* nID) % 1000;
std::this_thread::sleep_for(std::chrono::milliseconds(rand_time * 300));
CStdPrinter::PrintMsg("\t writer thread (%d) writer data (data: (%d) end....\n", nID, g_test_data);
}
//读者线程
void win_reader_thread(int nID)
{
while (1)
{
CStdPrinter::PrintMsg("读者线程(%d)进入等待状态...\n", nID);
AcquireSRWLockShared(&g_srwLock);
reader(nID);
ReleaseSRWLockShared(&g_srwLock);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
}
//写者线程
void win_writer_thread(int nID)
{
while (1)
{
CStdPrinter::PrintMsg("写者线程(%d)进入等待状态....\n", nID);
AcquireSRWLockExclusive(&g_srwLock);
writer(nID);
ReleaseSRWLockExclusive(&g_srwLock);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
//读写锁测试代码
void SRW_lock_instance()
{
const int READER_NUM = 5;
const int WRITER_NUM = 1;
InitializeSRWLock(&g_srwLock);//自动析构
std::thread arrThread[READER_NUM];
std::thread arrWriterThread[WRITER_NUM];
for (int i = 0; i < READER_NUM; i++)
{
arrThread[i] = std::thread(win_reader_thread, i + 1);
}
for (int i = 0; i < WRITER_NUM; i++)
{
arrWriterThread[i] = std::thread(win_writer_thread, i + 1);
}
for (int i = 0; i < WRITER_NUM; i++)
{
arrWriterThread[i].join();
}
for (int i = 0; i < READER_NUM; i++)
{
arrThread[i].join();
}
}
运行结果:
读者线程(1)进入等待状态...
reader thread(1) read begin....
读者线程(2)进入等待状态...
读者线程(3)进入等待状态...
reader thread(2) read begin....
读者线程(4)进入等待状态...
reader thread(3) read begin....
读者线程(5)进入等待状态...
reader thread(4) read begin....
写者线程(1)进入等待状态....
reader thread(5) read begin....
reader thread(1) read end (data : 0)....
reader thread(2) read end (data : 0)....
reader thread(3) read end (data : 0)....
reader thread(4) read end (data : 0)....
reader thread(5) read end (data : 0)....
writer thread (1) writer data begin....
writer thread (1) writer data (data: (467) end....
读者线程(2)进入等待状态...
读者线程(1)进入等待状态...
reader thread(2) read begin....
读者线程(3)进入等待状态...
reader thread(1) read begin....
读者线程(4)进入等待状态...
reader thread(3) read begin....
读者线程(5)进入等待状态...
reader thread(4) read begin....
reader thread(5) read begin....
写者线程(1)进入等待状态....
reader thread(2) read end (data : 467)....
reader thread(1) read end (data : 467)....
reader thread(3) read end (data : 467)....
reader thread(4) read end (data : 467)....
reader thread(5) read end (data : 467)....
writer thread (1) writer data begin....
读者线程(2)进入等待状态...
读者线程(1)进入等待状态...
读者线程(3)进入等待状态...
读者线程(4)进入等待状态...
读者线程(5)进入等待状态...
^C请按任意键继续. . .
参考资料:
https://blog.csdn.net/lwfcgz/article/details/8091242
https://blog.csdn.net/SpadgerZ/article/details/53045724
https://docs.microsoft.com/en-us/windows/desktop/sync/slim-reader-writer--srw--locks