I have two components which use interprocess communication:
ErrorController
Services:
- void ReportError(const std::string& str) throws (ServiceTempUnavailable);
- void ClearError(const std::string& str) throws (ServiceTempUnavailable);
References:
- can call TestComponent::SolveError
TestComponent
Services:
- void SolveError(const std::string& str) throws (ServiceTempUnavailable);
References:
- can call ErrorController::ReportError and ErrorController::ClearError
I develop TestComponent and I know that ErrorController locks the same mutex in each service (ReportError, ClearError) and when it calls SolveError (TestComponent service). Here are the most important parts of the code from TestComponent:
void TestComponent::SendError(const std::string& str)
{
std::lock_guard<std::mutex> guard(mtx_);
componentError_ = str;
clearError_ = false:
needUpdate_ = true;
cv_.notify_one();
}
//Next SendError will not be called if TestComponent has some unresolved error
bool TestComponent::HasError()
{
std::lock_guard<std::mutex> guard(mtx_);
return componentError_.empty() ? false : true;
}
//service impl - is called by ErrorController
void TestComponent::SolveError(const std::string& str)
{
std::lock_guard<std::mutex> guard(mtx_);
if(str == componentError_)
{
clearError_ = true;
needUpdate_ = true;
cv_.notify_one();
}
}
//errors processing is async (separate thread)
void TestComponent::ErrorProcessing()
{
while(componentStarted_.load())
{
std::unique_lock<std::mutex> guard(mtx_);
cv_.wait(guard, [this]{ return needUpdate_; });
while(needUpdate_)
{
if(!componentStarted_.load())
{
break;
}
if(clearError_)
{
try
{
ptr->ClearError(componentError);
}
catch(ServiceTempUnavailable ex)
{
guard.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
guard.lock();
continue;
}
needUpdate_ = false;
componentError_ = "";
//clearCallback can call SendError again
guard.unlock();
clearCallback();
}
else
{
try
{
ptr->ReportError(componentError);
}
catch(ServiceTempUnavailable ex)
{
guard.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
guard.lock();
continue;
}
needUpdate_ = false;
}
}
}
}
I need some tips how to improve my code. Above implementation may still leads to a deadlock:
- TestComponent SendError is called
- TestComponent locks the mutex in ErrorProcessing
- ErrorController calls SolveError (I assume in tests that SolveError can be called at any time - even if TestComponent hasn't reported an error)
- TestComponent can't call ReportError because ErrorController locks the mutex when it calls SolveError, SolveError waits for the mutex which is locked in ErrorProcessing function
Currently I can't change ErrorController implementation but maybe there should be used other locking strategy. How to fix TestComponent implementation ?
Aucun commentaire:
Enregistrer un commentaire