C++并发和互斥保护展示
最近要写一个多线程的并发数据库,主要是希望使用读写锁实现库的并发访问,同时考虑到其他平台(如Iar)没有C 的读写锁,需要操作系统提供,就将读写锁封装起来。整个过程还是比较曲折的,碰到了不少问题,在此就简单分析总结下并发和互斥吧。
首先,先贴上一部分源代码:
-
-
-
-
-
-
using cegn_mutex = std::shared_mutex;
-
cegn_mutex g_cegn_mutex;
-
void cegn_mutex_unique_lck(cegn_mutex& testmutex) //独占锁,写数据
-
{
-
std::unique_lock<cegn_mutex> cegn_lock(testmutex);
-
}
-
-
void cegn_mutex_share_lck(cegn_mutex& Dbmutex) //共享锁,读数据
-
{
-
std::shared_lock<cegn_mutex> cegn_lock(Dbmutex);
-
}
-
-
void cegn_mutex_unlck(cegn_mutex& Dbmutex)
-
{
-
; //vc读写锁离开作用域自动释放
-
}
-
-
int g_dwVal = 0;
-
void FastWriteData(int i)
-
{
-
while (1)
-
{
-
cegn_mutex_unique_lck(g_cegn_mutex);
-
g_dwVal ;
-
std::cout << "FastWriteData " << " Set dwVal= " << g_dwVal << "\n";
-
-
Sleep(1000);
-
cegn_mutex_unlck(g_cegn_mutex);
-
}
-
}
-
-
void SlowWriteData(int i)
-
{
-
while (1)
-
{
-
cegn_mutex_unique_lck(g_cegn_mutex);
-
g_dwVal ;
-
std::cout << "SlowWriteData " << " Set dwVal= " << g_dwVal << "\n";
-
Sleep(5000);
-
cegn_mutex_unlck(g_cegn_mutex);
-
}
-
}
-
-
void ReadData(int i)
-
{
-
while (1)
-
{
-
cegn_mutex_share_lck(g_cegn_mutex);
-
std::cout << "ReadData " << " Get dwVal= " << g_dwVal << "\n";
-
Sleep(500);
-
cegn_mutex_unlck(g_cegn_mutex);
-
}
-
}
-
-
int main()
-
{
-
std::cout << "main start !!" << std::endl;
-
-
std::thread thread1 = std::thread(FastWriteData, 0);
-
std::thread thread2 = std::thread(SlowWriteData, 0);
-
thread1.join();
-
thread2.join();
-
-
getchar();
-
return 1;
-
}
代码不长,逻辑也挺清晰的,但结果不正确:
似乎就没有互斥保护,因为FastWriteData和SlowWriteData中都独占了cegn_mutex_unique_lck(g_cegn_mutex);
且在while(1)中,不存在释放写锁的情况,那就不应该两个写线程交替出现。
如上让chatgpt分析下,它认为没啥问题,我尝试修改回标准读写锁接口,如下:
-
void FastWriteData(int i)
-
{
-
while (1)
-
{
-
// cegn_mutex_unique_lck(g_cegn_mutex);
-
std::unique_lock<cegn_mutex> lck(g_cegn_mutex);
-
g_dwVal ;
-
std::cout << "FastWriteData " << " Set dwVal= " << g_dwVal << "\n";
-
-
Sleep(1000);
-
cegn_mutex_unlck(g_cegn_mutex);
-
}
-
}
-
-
void SlowWriteData(int i)
-
{
-
while (1)
-
{
-
// cegn_mutex_unique_lck(g_cegn_mutex);
-
std::unique_lock<cegn_mutex> lck(g_cegn_mutex);
-
g_dwVal ;
-
std::cout << "SlowWriteData " << " Set dwVal= " << g_dwVal << "\n";
-
Sleep(5000);
-
cegn_mutex_unlck(g_cegn_mutex);
-
}
-
}
如上,代码运行就是正常了
-
main start !!
-
FastWriteData Set dwVal= 1
-
FastWriteData Set dwVal= 2
-
FastWriteData Set dwVal= 3
-
FastWriteData Set dwVal= 4
-
FastWriteData Set dwVal= 5
-
FastWriteData Set dwVal= 6
-
FastWriteData Set dwVal= 7
-
FastWriteData Set dwVal= 8
-
FastWriteData Set dwVal= 9
-
FastWriteData Set dwVal= 10
-
FastWriteData Set dwVal= 11
-
FastWriteData Set dwVal= 12
-
FastWriteData Set dwVal= 13
-
FastWriteData Set dwVal= 14
现在FastWriteData就独占了互斥量,导致SlowWriteData无法运行。为啥使用接口:
void cegn_mutex_unique_lck(cegn_mutex& testmutex) //独占锁,写数据
{
std::unique_lock<cegn_mutex> cegn_lock(testmutex);
}
就不行了?
修改成直接调用:
-
using cegn_mutex = std::shared_mutex;
-
cegn_mutex g_cegn_mutex;
-
void cegn_mutex_unique_lck(cegn_mutex& testmutex) //独占锁,写数据
-
{
-
// std::unique_lock<cegn_mutex> cegn_lock(testmutex);
-
std::unique_lock<cegn_mutex> cegn_lock(g_cegn_mutex);
-
}
还是不能正确互斥,修改如下也一样:
-
void cegn_mutex_unique_lck(cegn_mutex& testmutex) //独占锁,写数据
-
{
-
// std::unique_lock<cegn_mutex> cegn_lock(testmutex);
-
std::unique_lock<std::shared_mutex> cegn_lock(g_cegn_mutex);
-
}
经过分析,问题是:
void cegn_mutex_unique_lck(cegn_mutex& testmutex)
函数中定义了一个互斥量cegn_lock :
std::unique_lock<cegn_mutex> cegn_lock(testmutex);
该互斥量在函数退出的时候,生命周期就结束了,所以自动销毁,最终导致无法互斥,那是在想要封装,如何实现呢,可以自己协议个类封装:
完整的简单代码如下:
-
-
-
-
-
-
class MutexWrapper {
-
public:
-
MutexWrapper(std::mutex& mutex) : m_mutex(mutex) {
-
m_mutex.lock();
-
}
-
-
~MutexWrapper() {
-
m_mutex.unlock();
-
}
-
-
private:
-
std::mutex& m_mutex;
-
};
-
-
std::mutex g_mutex_test;
-
int g_dwVal = 0;
-
-
void FastWriteData(int i) {
-
while (1) {
-
MutexWrapper lock(g_mutex_test);
-
g_dwVal ;
-
std::cout << "FastWriteData " << " Set dwVal= " << g_dwVal << "\n";
-
Sleep(1000);
-
}
-
}
-
-
void SlowWriteData(int i) {
-
while (1) {
-
MutexWrapper lock(g_mutex_test);
-
g_dwVal ;
-
std::cout << "SlowWriteData " << " Set dwVal= " << g_dwVal << "\n";
-
Sleep(3000);
-
}
-
}
-
-
int main() {
-
std::cout << "main start !!" << std::endl;
-
-
std::thread thread1 = std::thread(FastWriteData, 0);
-
std::thread thread2 = std::thread(SlowWriteData, 0);
-
thread1.join();
-
thread2.join();
-
-
getchar();
-
return 1;
-
}
如此,运行正常了
修改下例程,让两个进程都整行跑
-
void FastWriteData(int i) {
-
while (1) {
-
{
-
MutexWrapper lock(g_mutex_test);
-
g_dwVal ;
-
std::cout << "FastWriteData " << " Set dwVal= " << g_dwVal << "\n";
-
}
-
Sleep(1000);
-
}
-
}
-
-
void SlowWriteData(int i) {
-
while (1) {
-
{
-
MutexWrapper lock(g_mutex_test);
-
g_dwVal ;
-
std::cout << "SlowWriteData " << " Set dwVal= " << g_dwVal << "\n";
-
}
-
Sleep(3000);
-
}
-
}
如上,代码就基本都正常了。
当然,也可以将互斥锁修改为读写锁,如下:
-
class MutexWrapper {
-
public:
-
MutexWrapper(std::shared_mutex& mutex) : m_mutex(mutex) {
-
m_mutex.lock();
-
}
-
-
~MutexWrapper() {
-
m_mutex.unlock();
-
}
-
-
private:
-
std::shared_mutex& m_mutex;
-
};
-
-
std::shared_mutex g_mutex_test;
代码也运行正常了。
综上:
1:基于RAII,C 的很多变量生命周期有限,必须特别注意智能变量的生命周期。
2:如果需要封装读写锁,不能简单函数分装,实在不行,就用一个类封装吧
3:要熟练掌握std::thread,std::shared_mutex,std::mutex的用法,这个是变法互斥基本要求
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhieefgh
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
excel下划线不显示怎么办
PHP中文网 06-23 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
微信运动停用后别人还能看到步数吗
PHP中文网 07-22 -
excel打印预览压线压字怎么办
PHP中文网 06-22