博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
三个线程同步中一个纠结的问题
阅读量:6234 次
发布时间:2019-06-21

本文共 6406 字,大约阅读时间需要 21 分钟。

前几天一直没想明白,搜索我的记忆海,愣是没找到这种三个线程相交互的!

 

1、问题描述

目前有三个class

WriteDB他主要负责把网页的信息写到数据中(间隔5分钟),每次更新之后都会他会相应的把DataOperation中的变量isDataUpdate_设置为true;

Search他负责处理对用户执行查询信息的操作,当有用户执行Search,他会相应的把DataOperation中的变量isUserSearch_设置为true;

DataOperation这是一个中间的类,负责做类WriteDB和类Search的同步操作,会一直检查这两个变量isDataUpdate_和isUserSearch_,当他们都为false的时候,把最新在内存中的数据库写入到对应的文件中,以便能够查询最新的信息,如果其中一个为true,他都等待。

 

2、迷糊的那段时间

也就是前几天,一直在想,怎么能实现上面的东西!一直被WriteDB这个class和isUserSearch_(bool类型)所困扰!

还写出来类似第一版的DataOperation代码:

 

class DataOperation{public:	DataOperation()	{		running_flag = true;		isDataUpdate_ = false;		isUserSearch_ = false;	}	void Stop()	{		running_flag = false;		{			boost::recursive_mutex::scoped_lock lock(mtx);			cond.notify_one();		}	}	void EmitSignalThread()	{		while (running_flag)		{			if (isSearchEnd_)			{				break;			}			{				boost::recursive_mutex::scoped_lock lock(mtx);				if (IsReplaceDB())				{					// 需要替换数据库					for (int i = 0; i <= 999; i++)					{						cout << "正在替换数据库" << i << endl;					}				}				cond.notify_all();			}			boost::this_thread::sleep(boost::posix_time::millisec(1000));		}	}	// 当后台有数据要更新,并且目前没有用户进行search的时候replace	// 返回true表明正在进行,false表示还需要等待	bool IsReplaceDB()	{			return (isDataUpdate_ && isUserSearch_);	}	// 这个会阻塞	void WaitReplaceDB()	{		boost::recursive_mutex::scoped_lock lock(mtx);		cout << "如果程序没有动静,那么表明此刻正在更新数据库...等待几秒即可!" << endl;		cond.wait(mtx);		boost::this_thread::sleep(boost::posix_time::millisec(100));	}	void SetIsDataUpdate(bool isDataUpdate = true)	{		isDataUpdate_ = isDataUpdate;	}	void SetIsUserSearch(bool isUserSearch = true)	{		isUserSearch_ = isUserSearch;	}	void SetIsSearchEnd(bool isSearchEnd = false)	{		isSearchEnd_ = isSearchEnd;	}	bool GetIsSearchEnd()	{		return isSearchEnd_;	}private:	bool running_flag;		// 数据助手是否需要存活	bool isDataUpdate_;		// 数据是否有更新	bool isUserSearch_;		// 当前是否有用户正在查询	bool isSearchEnd_;		// 程序是否已经退出	boost::recursive_mutex mtx;	boost::condition_variable_any cond;};

 

 

3、困扰的原因

 

我一直在想,以前的生产者和消费者是怎么做的?有没有想过还带有条件变量的?

 

4、能不能更简单

比如我就想过,只在DataOperation类中检测这两个bool变量,如果满足则更新DB,不满足Sleep;最终发现也有漏洞,毕竟这么做了Search中也要对应检测DB当前是否在更新,更新就Sleep----举一个极端的例子,但是是很可能发生:当前DataOperation发现没有用户在执行查询,那么DataOperation去设置标记(表面将要去更新数据库),当在设置标记的时候,用户更好输入了查询,发现数据库没在更新,那么就会造成同时出现DataOperation正在更新数据库、用户正在查询的情况!那么此时系统就会崩溃了。

 

5、所以说

条件变量、互斥量是确实有存在的意义的!

 

6、再来看一下整体的设计

从作用来看WriteDB只是自己做自己的,并不和多线程的同步有关,他仅仅是每次都设置isDataUpdate_为true就行;剩下的同步仅在于Search和Dataoperation中,bool isUserSearch_;bool isSearchEnd_;都没有实际的存在价值;只需要把isUserSearch_设置为条件变量就行。这样前面的两个bool变量的功能就被取代了(同时提一下,原来的条件变量,在这里才真正的用起来)

 

7、最终的测试代码

#include "iostream"#include "boost/thread.hpp"#include "boost/bind.hpp"using namespace std;#include "windows.h"#include "fstream"namespace MyNamespace{	ofstream cout("log.txt");}//#define WRITEFILE_NAMESPACE#ifdef WRITEFILE_NAMESPACEofstream out("log.txt");#endif // 0class DataOperation{public:	DataOperation()	{		running_flag_  = true;		isDataUpdate_  = false;	}	void Stop()	{		running_flag_ = false;	}	void EmitSignalThread()	{		while (running_flag_)		{			boost::recursive_mutex::scoped_lock lock(mtx);			bool flag = GetDataUpdate();			// 如果有更新 那些就替换数据库			if (GetDataUpdate())			{				// 需要替换数据库				for (int i = 0; i <= 999; i++)				{					if (i == 1)					{#ifdef WRITEFILE_NAMESPACE						out << "正在替换数据库" << i << endl;#else						cout << "正在替换数据库" << i << endl;#endif // WRITEFILE_NAMESPACE											}					if (i == 999)					{#ifdef WRITEFILE_NAMESPACE						out << "替换完毕" << i << endl;#else						cout << "替换完毕" << i << endl;#endif // WRITEFILE_NAMESPACE					}				}				isDataUpdate_ = false;			}			isUserSearch_.notify_all();			// 等待10秒钟,所以结束的时候可能会在这里阻塞	//		boost::this_thread::sleep(boost::posix_time::millisec(10000));		}	}	// 这个会阻塞	void WaitReplaceDB()	{		boost::recursive_mutex::scoped_lock lock(mtx);#ifdef WRITEFILE_NAMESPACE		out << "如果程序没有动静,那么表明此刻正在更新数据库...等待几秒即可!" << endl;#else		cout << "如果程序没有动静,那么表明此刻正在更新数据库...等待几秒即可!" << endl;#endif // WRITEFILE_NAMESPACE		isUserSearch_.wait(mtx);		boost::this_thread::sleep(boost::posix_time::millisec(100));	}	void SetDataUpdate(bool isDataUpdate = true)	{		isDataUpdate_ = isDataUpdate;	}	bool GetDataUpdate()	{		return isDataUpdate_;	}	bool GetRunningFlag()	{		return running_flag_;	}private:	bool running_flag_;							 // 数据助手是否需要存活	bool isDataUpdate_;			boost::recursive_mutex mtx;	boost::condition_variable_any isUserSearch_; // 当前是否有用户正在查询};class WriteDB{public:	void Start(DataOperation& dataoperation)	{		while (true)		{			// 在这里 这个线程进行数据库的更新可能需要大概好几分钟			for (int i = 0; i <= 9999; i++)			{				if (i == 1)				{#ifdef WRITEFILE_NAMESPACE					out << "WriteDB wait..." << i << endl;#else					cout << "WriteDB wait..." << i << endl;#endif // WRITEFILE_NAMESPACE				}				if (i == 9999)				{#ifdef WRITEFILE_NAMESPACE					out << "WriteDB wait..." << i << endl;#else					cout << "WriteDB wait..." << i << endl;#endif // WRITEFILE_NAMESPACE				}			}			dataoperation.SetDataUpdate();			// 查询一下,如果程序退出了,那么线程也退出			if (!dataoperation.GetRunningFlag())			{#ifdef WRITEFILE_NAMESPACE				out << "bye-bye" << endl;#else				cout << "bye-bye" << endl;#endif // WRITEFILE_NAMESPACE				break;			}			Sleep(10000);		}	}};class Search{public:	void Start(DataOperation& dataoperation)	{		string user_enter;		while (true)		{			getline(cin, user_enter);			if (user_enter == "q")			{				dataoperation.Stop();				break;			}#ifdef WRITEFILE_NAMESPACE			out << "当前用户输入的是:" << user_enter << endl;#else			cout << "当前用户输入的是:" << user_enter << endl;#endif // WRITEFILE_NAMESPACE			// 如果正在更新数据库,那么wait			dataoperation.WaitReplaceDB();		//	out << "如果程序没有动静,那么表明此刻正在更新数据库...等待几秒即可!" << endl;			// 如果没在更新数据库,直接进行查询			for (int i = 0; i <= 99999; i++)			{			//	cout << "正在为您查询数据..." << i << endl;				//				if (i == 1)				{#ifdef WRITEFILE_NAMESPACE					out << "正在为您查询数据..." << i << endl;#else					cout << "正在为您查询数据..." << i << endl;#endif // WRITEFILE_NAMESPACE				}				if (i == 99999)				{#ifdef WRITEFILE_NAMESPACE					out << "查询完毕..." << i << endl;#else					cout << "查询完毕..." << i << endl;#endif // WRITEFILE_NAMESPACE				}				//			}			// 向等待的线程发出信号,让他去更新数据库			Sleep(100);		}	}};int main(){	boost::thread_group grp;	WriteDB write_db;	Search search;	DataOperation data_operation; 	grp.create_thread(boost::bind(&WriteDB::Start, &write_db, boost::ref(data_operation)));	grp.create_thread(boost::bind(&Search::Start, &search, boost::ref(data_operation))); 	grp.create_thread(boost::bind(&DataOperation::EmitSignalThread, boost::ref(data_operation)));	grp.join_all();	return 0;}

 

你可能感兴趣的文章
图解 SQL 里的各种 JOIN
查看>>
2018 总结
查看>>
网页图标的优雅使用与总结
查看>>
iOS 录制视频时,添加水印
查看>>
工厂模式 抽象模式
查看>>
搞懂“分布式锁”,看这篇文章就对了
查看>>
1 序言 [全栈攻城师的技术札记]
查看>>
LeetCode之DI String Match(Kotlin)
查看>>
LeetCode之Two Sum IV Input is a BST(Kotlin)
查看>>
iOS 瀑布流之栅格布局
查看>>
Android中Activity的启动流程
查看>>
Parity钱包漏洞全分析及区块链安全风险应对措施
查看>>
到底是用"静态类"还是单例
查看>>
Redis RedLock 完美的分布式锁么?
查看>>
深入剖析Redis系列(八) - Redis数据结构之集合
查看>>
js:原生单张图片延迟加载(图片自己找)
查看>>
关于iOS中委托(Delegate)的几点看法
查看>>
读书笔记-Java高并发程序设计(一)
查看>>
spring cloud微服务分布式云架构 - Spring Cloud简介
查看>>
用vue-cli3导入外部的iconfont.css图标样式遇到的坑:These relative modules were not found:...
查看>>