问题描述:项目中有一个数据同步的函数,每隔2分钟被调用。
为了减少性能消耗,始终有两个线程去执行,线程之间通过ManualResetEvent
去传达信号. 先执行生产者线程,如果满足条件,通过ManualResetEvent.set
向消费者发出信号,消费者开始执行,执行完成后调用ManualResetEvent.WaitOne()
进行阻塞。
但问题是:第二次调用同步函数,却无法通过ManualResetEvent.set去唤醒线程。
详细的代码如下:
private static ManualResetEvent _mrePullData = new ManualResetEvent(false);//false初始化状态为无信号,将使WaitOne阻塞
private static Thread _producterThread = null; //生产者线程
private static Thread _costerThread = null; //消费者线程
public ApiResults PullDataFromCenterAMS() //这个函数每隔两分钟被调用
{
ApiResults result = new ApiResults();
result.message = "success";
_logger.LogInformation("调用PullDataFromCenterAMS");
try
{
if (_producterThread == null) //第一次调用,创建线程
{
_producterThread = new Thread(new ThreadStart(Product));
_producterThread.Name = "Product";
_producterThread.Start();
_costerThread = new Thread(new ThreadStart(Cost));
_costerThread.Name = "Cost";
_costerThread.Start();
}
else //第二次执行时,不再创建线程
{
_mrePullData.Set(); //但是这里却没有办法唤醒生产者线程,也就是说无法调用Product()
}
return result;
}
catch (Exception ex)
{
result.message = "faile:" + ex.Message;
return result;
}
}
/// <summary>
/// 生产线
/// </summary>
private void Product()
{
/*判断libraryCode是否有效,需要同步的数据是否存在,符合条件才打开信号*/
string libraryCode = Appsettings.app(new string[] { "App", "LibraryCode" });
_libraryModel = DAOControls.DAOControlsInit().GetLibraryByCode(libraryCode);
if (_libraryModel == null)
{
_logger.LogInformation("图书馆代码无效,找不到对应的图书馆");
_mrePullData.WaitOne(); //没有同步对象,即无信号,则会阻塞
}
else
{
_libraryName = _libraryModel.LibraryCName;
_mrePullData.Set();//表示有信号了,通知WaitOne不再阻塞
Thread.Sleep(100);
}
}
/// <summary>
/// 消费线
/// </summary>
private async void Cost()
{
/*
通过http请求去同步数据,并将同步结果进行日志输出,如果遇到同步错误或者同步完成,将调用_mrePullData.WaitOne()进行阻塞
*/
SyncResp syncResp = await _syncDataRequestServices.PullSysncDataOrder(_httpClientFactory, _syncDataURL, _libraryName, _lastSyncTime);
if (syncResp.SyncResult.StartsWith("Fail")) //拉取数据过程中报错,此时输出日志,中断同步
{
_logger.LogInformation(syncResp.SyncResult);
_mrePullData.WaitOne();
return;
}
else
{
if (syncResp.SyncResult.StartsWith("TotalSyncFinished")) //所有的表都已同步完成,此时输出日志,中断同步
{
_logger.LogInformation(syncResp.SyncResult);
_mrePullData.WaitOne();
return;
}
else
{
if (syncResp.SyncResult.StartsWith("TableSyncFinished")) //某个表同步完成,此时输出日志,继续同步其它表
{
_logger.LogInformation(syncResp.SyncResult);
}
else
{
List<Audit> audits = syncResp.SyncResult.FromJsonString<List<Audit>>();
string msg = await UpdateDataToDB(audits);
if (msg == "success")
{
_logger.LogInformation("此页数据成功同步到DB,继续同步");
}
else
{
_logger.LogInformation("数据同步至DB时报错:" + msg + "请修复问题,同步中断");
_mrePullData.WaitOne();
return;
}
}
ExecuteSyncOrder(); //继续同步
}
}
}
提出问题:ManualResetEvent.set()失效的原因是什么,有什么解决办法呢, 或者是否有其它实现方案
恳请大家指点,不胜感激,期待,谢谢!