DynExp
Highly flexible laboratory automation for dynamically changing experiments.
Object.cpp
Go to the documentation of this file.
1 // This file is part of DynExp.
2 
3 #include "stdafx.h"
4 #include "Object.h"
5 #include "DynExpCore.h"
6 
7 namespace DynExp
8 {
9  Util::ILockable::LockType ObjectUserList::AcquireLock(const std::chrono::milliseconds Timeout) const
10  {
11  return ILockable::AcquireLock(Timeout);
12  }
13 
14  void ObjectUserList::Register(const Object& User, const std::chrono::milliseconds Timeout)
15  {
16  auto lock = AcquireLock(Timeout);
17 
18  RegisterUnsafe(User);
19  }
20 
22  {
23  RegisterUnsafe(User);
24 
25  return std::move(Lock);
26  }
27 
28  void ObjectUserList::Deregister(const Object& User, const std::chrono::milliseconds Timeout)
29  {
30  auto lock = AcquireLock(Timeout);
31 
32  DeregisterUnsafe(User);
33  }
34 
35  size_t ObjectUserList::CountUsers(const std::chrono::milliseconds Timeout) const
36  {
37  auto lock = AcquireLock(Timeout);
38 
39  return CountUsersUnsafe();
40  }
41 
42  ItemIDListType ObjectUserList::GetUserIDs(std::chrono::milliseconds Timeout) const
43  {
44  auto lock = AcquireLock(Timeout);
45 
46  return GetUserIDsUnsafe();
47  }
48 
49  std::string ObjectUserList::GetUserNamesString(const std::chrono::milliseconds Timeout) const
50  {
51  auto lock = AcquireLock(Timeout);
52 
53  return GetUserNamesStringUnsafe();
54  }
55 
57  {
58  for (auto& User : UserList)
59  User.first->CheckLinkedObjectStates();
60 
61  UserList.clear();
62  }
63 
65  {
66  return std::accumulate<decltype(UserList.cbegin()), size_t>(UserList.cbegin(), UserList.cend(),
67  0, [](size_t CurrentValue, const auto& User) {
68  return CurrentValue + User.second;
69  });
70  }
71 
73  {
74  ItemIDListType IDs;
75 
76  for (const auto& User : UserList)
77  IDs.push_back(User.first->GetID());
78 
79  return IDs;
80  }
81 
83  {
84  std::string Names("Items making use of this item:");
85  for (const auto& User : UserList)
86  Names += "\n- " + User.first->GetObjectName() + " (" + User.first->GetCategoryAndName() + ")";
87 
88  return Names;
89  }
90 
92  {
93  auto& Value = UserList[&User];
94 
95  if (Value == std::numeric_limits<std::remove_reference_t<decltype(Value)>>::max())
96  throw Util::OverflowException("Cannot increment the user list counter since an overflow would occur.");
97 
98  ++Value;
99  }
100 
102  {
103  auto ValueIt = UserList.find(&User);
104  if (ValueIt == UserList.cend())
105  return;
106 
107  if (ValueIt->second == 0)
108  throw Util::UnderflowException("Cannot decrement the user list counter since an underflow would occur.");
109  if (--ValueIt->second == 0)
110  UserList.erase(ValueIt);
111  }
112 
114  std::string ParamName, std::string_view ParamTitle, std::string_view ParamDescription, bool NeedsResetToApplyChange)
115  : ParamsBaseOnly(*this), Owner(Owner), UserEditable(true),
116  ParamName(ParamName), ParamTitle(ParamTitle), ParamDescription(ParamDescription), NeedsResetToApplyChange(NeedsResetToApplyChange)
117  {
118  // Since classes derived from ParamBase are declared within the scope of class ParamsBase, this is allowed.
119  // This is safe since OwnedParams is declared before any member derived from ParamBase within the inheritance hierarchy.
120  // Intended call to a virtual function (Owner.GetParamClassTag()) during construction of ParamsBase. See declaration of
121  // ParamsBase::GetParamClassTag().
122  Owner.OwnedParams.emplace_back(Owner.GetParamClassTag(), std::ref(*this));
123  }
124 
125  ParamsBase::ParamBase::ParamBase(ParamsBase& Owner, std::string ParamName)
126  : ParamsBaseOnly(*this), Owner(Owner), UserEditable(false),
127  ParamName(ParamName), NeedsResetToApplyChange(false)
128  {
129  // See above.
130  Owner.OwnedParams.emplace_back(Owner.GetParamClassTag(), std::ref(*this));
131  }
132 
134  {
135  }
136 
137  QDomElement ParamsBase::ParamBase::ToXMLNode(QDomDocument& Document) const
138  {
139  QDomElement Node = Document.createElement(GetParamName().data());
140  ToXMLNodeChild(Document, Node);
141 
142  return Node;
143  }
144 
145  void ParamsBase::ParamBase::FromXMLNode(const QDomElement& XMLElement)
146  {
147  try
148  {
149  FromXMLNodeChild(XMLElement);
150  }
151  catch ([[maybe_unused]] const Util::NotFoundException& e)
152  {
153  Reset();
154 
155  Util::EventLog().Log("Parameter \"" + std::string(GetParamName()) + "\" has not been found in configuration file. Assuming default value.",
157  }
158  catch (...)
159  {
160  throw;
161  }
162  }
163 
165  {
166  bool IsValid = ValidateChild();
167 
168  if (!IsValid)
169  {
170  Reset();
171 
172  Util::EventLog().Log("Parameter \"" + std::string(GetParamName()) + "\" has been reset to its default value since it was invalid.",
174  }
175 
176  return IsValid;
177  }
178 
180  {
181  if (CurrentParam == Params.ObjectLinkParams.cend())
182  return true;
183 
184  if (!EnsureReadyStateCalledForCurrentParam)
185  {
186  CurrentParam->get().EnsureReadyState();
187  EnsureReadyStateCalledForCurrentParam = true;
188  }
189  else if (CurrentParam->get().IsReady())
190  {
191  ++CurrentParam;
192  EnsureReadyStateCalledForCurrentParam = false;
193  }
194 
195  return false;
196  }
197 
199  {
200  }
201 
202  QDomElement ParamsBase::ConfigToXML(QDomDocument& Document) const
203  {
204  QDomElement MainNode = Document.createElement(ParamsBase::GetParamClassTag());
205  QDomElement CurrentNode = MainNode; // shallow copy
206 
207  for (const auto& OwnedParam : OwnedParams)
208  {
209  if (CurrentNode.tagName() != OwnedParam.ClassTag)
210  {
211  QDomElement SubNode = Document.createElement(OwnedParam.ClassTag);
212  CurrentNode = CurrentNode.appendChild(SubNode).toElement();
213  }
214 
215  if (!OwnedParam.OwnedParam.get().GetParamName().empty())
216  CurrentNode.appendChild(OwnedParam.OwnedParam.get().ToXMLNode(Document));
217  }
218 
219  return MainNode;
220  }
221 
222  void ParamsBase::ConfigFromXML(const QDomElement& XMLElement) const
223  {
224  QDomElement CurrentNode = Util::GetSingleChildDOMElement(XMLElement, ParamsBase::GetParamClassTag());
225 
226  for (const auto& OwnedParam : OwnedParams)
227  {
228  try
229  {
230  if (CurrentNode.tagName() != OwnedParam.ClassTag)
231  CurrentNode = Util::GetSingleChildDOMElement(CurrentNode, OwnedParam.ClassTag);
232  }
233  catch ([[maybe_unused]] const Util::NotFoundException& e)
234  {
235  std::string MissingParamName(OwnedParam.OwnedParam.get().GetParamName());
236  Util::EventLog().Log("Node \"" + std::string(OwnedParam.ClassTag) +
237  "\" has not been found in configuration file." +
238  (MissingParamName.empty() ? "" :
239  (" Assuming default value for parameter \"" + MissingParamName + "\".")),
241 
242  // Assume default values if hierarchy levels in the XML structure are missing.
243  // Params classes without any parameters do get reflected in the XML hierarchy.
244  OwnedParam.OwnedParam.get().Reset();
245 
246  continue;
247  }
248  catch (...)
249  {
250  throw;
251  }
252 
253  if (!OwnedParam.OwnedParam.get().GetParamName().empty())
254  OwnedParam.OwnedParam.get().FromXMLNode(CurrentNode);
255  }
256 
257  Validate();
258  }
259 
261  {
262  ConfigureParams();
263 
264  for (const auto& OwnedParam : OwnedParams)
265  if (OwnedParam.OwnedParam.get().IsUserEditable())
266  OwnedParam.OwnedParam.get().ParamsBaseOnly.AddToDialog(Dialog);
267 
268  Validate();
269  }
270 
271  bool ParamsBase::Validate() const
272  {
273  bool AllValid = true;
274 
275  std::for_each(OwnedParams.cbegin(), OwnedParams.cend(), [&AllValid](auto OwnedParams) {
276  AllValid &= OwnedParams.OwnedParam.get().Validate();
277  });
278 
279  return AllValid;
280  }
281 
283  {
285  { "Allow usage by only a single other item", UsageType::Unique },
286  { "Allow usage by multiple other items", UsageType::Shared }
287  };
288 
289  return List;
290  }
291 
293  {
294  Param.ParamsBaseOnly.DisableUserEditable();
295  }
296 
298  {
299  if (!ConfigureUsageType())
301 
303  }
304 
305  std::filesystem::path ParamsBase::ToAbsolutePath(const std::filesystem::path& Path) const
306  {
307  return GetCore().ToAbsolutePath(Path);
308  }
309 
311  {
312  }
313 
315  {
316  auto Params = MakeParams(ID, Core);
317  auto ConfigDlg = std::make_unique<ParamsConfigDialog>(DialogParent, Core, std::string("New ") + Params->ObjectName.Get());
318 
319  Params->ConfigFromDialog(*ConfigDlg);
320 
321  return ConfigDlg->Display() ? std::move(Params) : nullptr;
322  }
323 
325  {
326  auto Params = MakeParams(ID, Core);
327 
328  Params->ConfigFromXML(XMLElement);
329 
330  return Params;
331  }
332 
334  QWidget* const DialogParent) const
335  {
336  std::unique_ptr<ParamsConfigDialog> ConfigDlg;
337 
338  {
339  auto ParamsPtr = Obj->GetParams();
340  ConfigDlg = std::make_unique<ParamsConfigDialog>(DialogParent, Core, std::string("Edit ") + ParamsPtr->ObjectName.Get());
341 
342  ParamsPtr->ConfigFromDialog(*ConfigDlg);
343  } // Params unlocked here. ParamsConfigDialog::accept() locks itself again when user has accepted.
344 
345  auto Accepted = ConfigDlg->Display(Obj);
346 
347  return { Accepted, ConfigDlg->IsResetRequired() };
348  }
349 
350  std::string Object::CategoryAndNameToStr(const std::string& Category, const std::string& Name)
351  {
352  if (Category.empty())
353  return Name;
354  else
355  return Category + " -> " + Name;
356  }
357 
358  Object::Object(const std::thread::id OwnerThreadID, ParamsBasePtrType&& Params)
359  : LinkedObjectWrapperOnly(*this), OwnerThreadID(OwnerThreadID), Params(std::move(Params))
360  {
361  if (OwnerThreadID == std::thread::id())
362  throw Util::InvalidArgException("OwnerThreadID is not a valid thread identifier.");
363 
364  if (!this->Params)
365  throw Util::InvalidArgException("Params cannot be nullptr.");
366  }
367 
369  {
370 #ifdef DYNEXP_DEBUG
371  Util::EventLog().Log("Item \"" + GetObjectName() + "\" is being removed.");
372 #endif // DYNEXP_DEBUG
373  }
374 
375  void Object::LinkedObjectWrapperOnlyType::RegisterUser(const Object& User, const std::chrono::milliseconds Timeout) const
376  {
377  // Longer timeout in case a module is started which itself starts an instrument (empiric value...)
378  // since the instrument might have locked its Params while starting up.
379  // If longer timeout is not allowed, this might throw Util::TimeoutException.
380  auto IsSharedUsage = Parent.IsSharedUsageEnabled(std::chrono::milliseconds(1000));
381 
382  // Now, race condition between Object::IsReady() and Object::BlockIfUnused() is avoided.
383  auto lock = Parent.UserList.AcquireLock(Timeout);
384 
385  // Just a check for the moment, no guarantee, that the required object stays in a healthy state...
386  if (!Parent.IsReady())
387  throw Util::InvalidStateException("The required item is in an invalid state or in an error state.");
388 
389  if (!IsSharedUsage && !Parent.IsUnusedUnsafe())
391  "According to the item's \"Usage type\" setting, it can only be used by a single other item. Since it is already in use, it cannot be used by another item."
392  + std::string("\n\n") + Parent.UserList.GetUserNamesStringUnsafe(),
394 
395  Parent.UserList.Register(User, std::move(lock));
396  }
397 
398  void Object::LinkedObjectWrapperOnlyType::DeregisterUser(const Object& User, const std::chrono::milliseconds Timeout) const
399  {
400  Parent.UserList.Deregister(User, Timeout);
401  }
402 
404  {
406 
407  // Now, objects trying to make use of this object cannot register themselves here anymore.
408  // They have to wait until reset is done.
409  auto lock = UserList.AcquireLock();
410 
411  if (!IsUnusedUnsafe())
413  "This item is currently being used by at least another item. Stop and reset these items before resetting this item."
414  + std::string("\n\n") + UserList.GetUserNamesStringUnsafe());
415 
416  ClearWarning();
417 
419  }
420 
421  void Object::BlockIfUnused(const std::chrono::milliseconds Timeout)
422  {
424 
425  // Now, race condition between Object::IsReady() and Object::BlockIfUnused() is avoided.
426  auto lock = UserList.AcquireLock(Timeout);
427 
428  if (!IsUnusedUnsafe())
430  "This item is currently being used by at least another item. Stop and reset these items before deleting this item."
431  + std::string("\n\n") + UserList.GetUserNamesStringUnsafe());
432 
433  IsBlocked = true;
434  }
435 
436  Object::ParamsConstTypeSyncPtrType Object::GetParams(const std::chrono::milliseconds Timeout) const
437  {
439  }
440 
441  Object::ParamsTypeSyncPtrType Object::GetParams(const std::chrono::milliseconds Timeout)
442  {
443  return ParamsTypeSyncPtrType(Params.get(), Timeout);
444  }
445 
446  void Object::EnsureReadyState(bool IsAutomaticStartup)
447  {
448  // EnsureCallFromOwningThread(); does not work here because hardware adapters are connected asynchronously
449  // from another thread in DynExpManager::OnRunProject().
450 
451  EnsureReadyStateChild(IsAutomaticStartup);
452  }
453 
454  void Object::SetWarning(std::string Description, int ErrorCode) const
455  {
456  Warning = Util::Warning(std::move(Description), ErrorCode);
457 
458  LogWarning();
459  }
460 
461  void Object::SetWarning(const Util::Exception& e) const
462  {
463  Warning = e;
464 
465  LogWarning();
466  }
467 
469  {
470  if (std::this_thread::get_id() != OwnerThreadID)
472  "This function must be called from the thread managing this object. A call from another instrument or module thread is not supported.");
473  }
474 
475  Object::ParamsTypeSyncPtrType Object::GetNonConstParams(const std::chrono::milliseconds Timeout) const
476  {
477  return ParamsTypeSyncPtrType(Params.get(), Timeout);
478  }
479 
480  void Object::LogWarning() const
481  {
483  }
484 
486  {
487  }
488 
490  {
492  { "Start item as soon as it is created", RunnableObjectParams::StartupType::OnCreation },
493  { "Start item as soon as it is required by another item", RunnableObjectParams::StartupType::Automatic },
494  { "Start item only manually", RunnableObjectParams::StartupType::Manual }
495  };
496 
497  return List;
498  }
499 
501  {
502  if (!ConfigureStartupType())
503  DisableUserEditable(Startup);
504 
505  ConfigureParamsImpl(dispatch_tag<RunnableObjectParams>());
506  }
507 
509  {
510  }
511 
513  {
514  return "This item is currently being used by at least another item. Stop and reset these items before stopping this item."
515  + std::string("\n\n") + GetUserNames().data();
516  }
517 
519  : Object(OwnerThreadID, std::move(Params)), RunnableInstanceOnly(*this)
520  {
521  Init();
522  }
523 
525  {
526  try
527  {
528  // Better call terminate before destruction manually to handle errors.
529  TerminateImpl(false);
530  }
531  catch (const Util::TimeoutException& e)
532  {
533  Util::EventLog().Log(e);
534  Util::EventLog().Log("Could not terminate thread in the runnable's destructor. Timeout occurred. Execution cannot continue.",
536 
537  std::terminate();
538  }
539  catch (const Util::NotAvailableException& e)
540  {
541  // Should never happen since modules are destroyed first in DynExpCore.
542  Util::EventLog().Log(e);
543  Util::EventLog().Log("Could not terminate thread in the runnable's destructor. The runnable is still in use. Execution cannot continue.",
545 
546  std::terminate();
547  }
548  }
549 
550  bool RunnableObject::Run(QWidget* ParentWidget)
551  {
553 
554  if (GetException())
556  "A runnable is in an error state. It requires to be reset in order to transition into a ready state.");
557 
558  auto StartupDialog = MakeStartupBusyDialogChild(ParentWidget);
559  int Result = QDialog::Accepted;
560  if (StartupDialog)
561  {
562  auto Params = GetParams();
563  ParamsBase::LinkParamStarter LinkParamStarter(*Params);
564  StartupDialog->SetCheckFinishedFunction(LinkParamStarter);
565 
566  // StartupDialog->exec() blocks and starts new event loop for the modal dialog (in the same thread).
567  Result = StartupDialog->exec();
568  }
569 
570  if (StartupDialog && Result != QDialog::Accepted)
571  {
572  if (StartupDialog->GetException())
573  std::rethrow_exception(StartupDialog->GetException());
574 
575  return false;
576  }
577  if (IsRunning())
578  return false;
579 
580  // Always call Reset() before starting to allow using Reset() for initialization.
581  // 'if (IsExiting())' could in principle be used here to determine whether the
582  // RunnableObject is not being started for the first time.
583  Reset();
584 
585  auto Params = dynamic_Params_cast<RunnableObject>(GetParams());
586  Startup = Params->Startup;
587 
588  RunChild();
589  Running = true;
590 
591  return true;
592  }
593 
595  {
596  auto Params = dynamic_Params_cast<RunnableObject>(GetParams());
597 
598  if (Params->Startup == RunnableObjectParams::StartupType::Automatic)
599  return Run();
600  else if (!IsRunning())
601  throw Util::NotAvailableException("The required item " + Params->ObjectName.Get() + " (" + GetCategoryAndName() +
602  ") cannot be started since automatic startup has been disabled for this item.", Util::ErrorType::Error);
603 
604  return false;
605  }
606 
608  {
609  auto Params = dynamic_Params_cast<RunnableObject>(GetParams());
610 
611  if (Params->Startup == RunnableObjectParams::StartupType::OnCreation)
612  return Run();
613 
614  return false;
615  }
616 
617  void RunnableObject::Terminate(bool Force, const std::chrono::milliseconds Timeout)
618  {
620 
621  TerminateImpl(Force, Timeout);
622  }
623 
624  void RunnableObject::SetPaused(bool Pause, std::string Description)
625  {
626  Paused = Pause;
627 
628  if (Pause)
629  SetReasonWhyPaused(std::move(Description));
630  else
632  }
633 
635  {
636  Running = false;
637  Paused = false;
639  ShouldExit = false;
641  }
642 
644  {
645  std::promise<void> ThreadExitedPromise;
646  ThreadExitedSignal = ThreadExitedPromise.get_future();
647 
648  return ThreadExitedPromise;
649  }
650 
651  void RunnableObject::StoreThread(std::thread&& Thread) noexcept
652  {
653  this->Thread = std::move(Thread);
654  }
655 
657  {
658  return std::this_thread::get_id() == Thread.get_id();
659  }
660 
662  {
665  "This function must be called from this runnable's thread. A call from another thread is not supported.");
666  }
667 
669  {
670  TerminateUnsafe(false);
671 
673  Init();
674  }
675 
676  void RunnableObject::EnsureReadyStateChild(bool IsAutomaticStartup)
677  {
678  IsAutomaticStartup ? RunIfRunAutomatic() : RunIfRunOnCreation();
679  }
680 
681  void RunnableObject::TerminateImpl(bool Force, const std::chrono::milliseconds Timeout)
682  {
683  // Now, objects trying to make use of this object cannot register themselves here anymore.
684  auto lock = LockUserList();
685  auto IsUnused = IsUnusedUnsafe();
686 
687  if (!Force && !IsUnused)
688  throw NotUnusedException(*this);
689 
690  if (!IsUnused)
692  TerminateUnsafe(Force, Timeout);
693  }
694 
695  void RunnableObject::TerminateUnsafe(bool Force, const std::chrono::milliseconds Timeout)
696  {
697  if (!Thread.joinable())
698  return;
699 
701 
702  ShouldExit = true;
703  NotifyChild();
704  if (ThreadExitedSignal.wait_for(Timeout) != std::future_status::ready)
706 
707  Thread.join();
708  Thread = std::thread();
709  Running = false;
710  Paused = false;
711  }
712 
714  {
715  // Just indicate status changes. All the clean up is performed in the main thread when
716  // 1) Terminate() is called (calls TerminateUnsafe(), Thread is still joinable)
717  // 2) Reset() is called (calls TerminateUnsafe())
718  // 3) Run() is called (it calls Reset())
719  // There is no race condition since TerminateChild() also sets Running to false and
720  // Running is not read in between (IsRunning() is not called).
721  ShouldExit = true;
722  Running = false;
723  Paused = false;
724 
725  // This is necessary if the RunnableObject is not terminated regularly but by an error.
727  }
728 
730  {
731  }
732 
734  {
735  return Owner.GetOwner();
736  }
737 
739  {
740  }
741 
743  {
744  ResetChild();
745 
747  }
748 
750  {
751  }
752 
753  RunnableInstance::RunnableInstance(RunnableObject& Owner, std::promise<void>&& ThreadExitedPromise)
754  : ParamsGetter({ Owner, &Object::GetParams, { Object::GetParamsTimeoutDefault } }),
755  Owner(Owner), ThreadExitedPromise(std::move(ThreadExitedPromise))
756  {
757  }
758 
759  // Not noexcept since move-constructor of std::list is not noexcept.
761  : ParamsGetter(Other.ParamsGetter), Owner(Other.Owner), ThreadExitedPromise(std::move(Other.ThreadExitedPromise)),
762  OwnedLinkedObjectWrappers(std::move(Other.OwnedLinkedObjectWrappers))
763  {
764  Other.Empty = true;
765  }
766 
768  {
769  SetThreadExited();
770 
771  std::for_each(OwnedLinkedObjectWrappers.cbegin(), OwnedLinkedObjectWrappers.cend(), [](const auto& i) {
772  i.OwnedLinkedObjectWrapperContainer.Reset();
773  });
774  }
775 
777  {
778  bool AnyDestinyNotReady = false;
779 
780  if (GetOwner().RunnableInstanceOnly.IsLinkedObjStateCheckRequested())
781  {
782  GetOwner().RunnableInstanceOnly.ResetLinkedObjStateCheckRequested();
783 
784  for (auto& Wrapper : OwnedLinkedObjectWrappers)
785  Wrapper.OwnedLinkedObjectWrapperContainer.CheckIfReady();
786  }
787 
788  for (auto& Wrapper : OwnedLinkedObjectWrappers)
789  {
790  if (Wrapper.OwnedLinkedObjectWrapperContainer.GetState() == LinkedObjectWrapperContainerBase::LinkedObjectStateType::NotReady)
791  {
792  AnyDestinyNotReady = true;
793 
794  if (Wrapper.OwnedLinkedObjectWrapperPtr->IsRegistered())
795  Wrapper.OwnedLinkedObjectWrapperPtr->Deregister(std::chrono::milliseconds(100));
796  else
797  {
798  try
799  {
800  Wrapper.OwnedLinkedObjectWrapperPtr->Register(ObjectLinkBase::LockObjectTimeoutDefault);
801  Wrapper.OwnedLinkedObjectWrapperContainer.LinkedObjectState = LinkedObjectWrapperContainerBase::LinkedObjectStateType::Ready;
802  }
803  catch (...)
804  {
805  // Registering failed because underlying object is still in an error state.
806  // Swallow the exception and try again next time this function is called.
807  }
808  }
809  }
810  }
811 
812  return !AnyDestinyNotReady;
813  }
814 
816  {
817  std::string Names("Linked items not being in a ready state:");
818  for (auto& Wrapper : OwnedLinkedObjectWrappers)
819  if (Wrapper.OwnedLinkedObjectWrapperContainer.GetState() == LinkedObjectWrapperContainerBase::LinkedObjectStateType::NotReady)
820  Names += "\n- " + Wrapper.OwnedLinkedObjectWrapperContainer.GetLinkedObjectDesc();
821 
822  return Names;
823  }
824 
826  {
827  if (!Empty)
828  {
829  // ThreadExitedPromise.set_value_at_thread_exit(); does not work, because
830  // ThreadExitedSignal.wait_for(Timeout) in InstrumentBase::Terminate() would not
831  // return in case of timeout since the value is already stored.
832  ThreadExitedPromise.set_value();
833 
834  GetOwner().RunnableInstanceOnly.OnThreadHasExited();
835  }
836  }
837 }
Defines DynExp's core module as an interface between the UI and DynExp objects.
Implementation of DynExp objects as the base for derived resources and implementation of the object p...
virtual ~ConfiguratorBase()=0
Definition: Object.cpp:310
ParamsBasePtrType MakeConfigFromXML(ItemIDType ID, const DynExpCore &Core, const QDomElement &XMLElement) const
Retrieves the configuration from an XML node to create an instance of the related Object's parameter ...
Definition: Object.cpp:324
ParamsBasePtrType MakeConfigFromDialog(ItemIDType ID, const DynExpCore &Core, QWidget *const DialogParent) const
Sets up and displays a configuration dialog. The user input is used to create an instance of the rela...
Definition: Object.cpp:314
UpdateConfigFromDialogResult UpdateConfigFromDialog(Object *Obj, const DynExpCore &Core, QWidget *const DialogParent) const
Updates an Object's Obj parameters from a configuration dialog. Sets up and displays this dialog.
Definition: Object.cpp:333
DynExp's core class acts as the interface between the user interface and DynExp's internal data like ...
Definition: DynExpCore.h:127
const Object & GetOwner() const noexcept
Returns the owner of this wrapper.
Definition: Object.cpp:733
virtual ~LinkedObjectWrapperBase()=0
Definition: Object.cpp:729
const RunnableInstance & Owner
Instance of class RunnableInstance managing the wrapper.
Definition: Object.h:2809
void Reset() noexcept
Removes any linked LinkedObjectWrapper and updates LinkedObjectState.
Definition: Object.cpp:742
LinkedObjectStateType LinkedObjectState
Stores the current state of this LinkedObjectWrapperContainerBase instance. Refer to LinkedObjectStat...
Definition: Object.h:3117
virtual void ResetChild() noexcept=0
Removes any linked LinkedObjectWrapper and updates LinkedObjectState.
virtual ~ObjectLinkBase()=0
Definition: Object.cpp:749
static constexpr std::chrono::milliseconds LockObjectTimeoutDefault
Default timeout used by classes ObjectLinkt and RunnableInstance to be passed to LinkedObjectWrapper:...
Definition: Object.h:3359
std::string GetUserNamesString(std::chrono::milliseconds Timeout=std::chrono::milliseconds(0)) const
Builds a string describing which users are registered containing their object names,...
Definition: Object.cpp:49
void Deregister(const Object &User, const std::chrono::milliseconds Timeout=std::chrono::milliseconds(0))
Deregisters a user in a thread-safe way.
Definition: Object.cpp:28
std::string GetUserNamesStringUnsafe() const
Definition: Object.cpp:82
void Register(const Object &User, const std::chrono::milliseconds Timeout=std::chrono::milliseconds(0))
Registers a user in a thread-safe way.
Definition: Object.cpp:14
std::unordered_map< const Object *, size_t > UserList
Map containing pointers to all users making use of this ObjectUserList instance's owner as keys and t...
Definition: Object.h:176
void DeregisterAllUnsafe()
Deregisters all users and notifies them that they need to check the states of their used linked objec...
Definition: Object.cpp:56
size_t CountUsersUnsafe() const
Definition: Object.cpp:64
size_t CountUsers(std::chrono::milliseconds Timeout=std::chrono::milliseconds(0)) const
Counts the registered useres in a thread-safe way.
Definition: Object.cpp:35
ItemIDListType GetUserIDsUnsafe() const
Definition: Object.cpp:72
void DeregisterUnsafe(const Object &User)
Deregisters a user.
Definition: Object.cpp:101
void RegisterUnsafe(const Object &User)
Registers a user.
Definition: Object.cpp:91
Util::ILockable::LockType AcquireLock(const std::chrono::milliseconds Timeout=DefaultTimeout) const
Locks the user list for thread-safe manipulation.
Definition: Object.cpp:9
ItemIDListType GetUserIDs(std::chrono::milliseconds Timeout=std::chrono::milliseconds(0)) const
Returns a list of the IDs of the registered users in a thread-safe way.
Definition: Object.cpp:42
void DeregisterUser(const Object &User, const std::chrono::milliseconds Timeout) const
Deregisters a user in a thread-safe way.
Definition: Object.cpp:398
Object & Parent
Owning Object instance.
Definition: Object.h:2068
void RegisterUser(const Object &User, const std::chrono::milliseconds Timeout) const
Registers a user in a thread-safe way.
Definition: Object.cpp:375
Base class for all DynExp Objects like hardware adapters (DynExp::HardwareAdapterBase),...
Definition: Object.h:1971
Object(const std::thread::id OwnerThreadID, ParamsBasePtrType &&Params)
Constructs an Object instance.
Definition: Object.cpp:358
void SetWarning(std::string Description, int ErrorCode) const
Setter for Object::Warning. Sets the warning by a description and an error code.
Definition: Object.cpp:454
ParamsConstTypeSyncPtrType GetParams(const std::chrono::milliseconds Timeout=GetParamsTimeoutDefault) const
Locks the mutex of the parameter class instance Params assigned to this Object instance and returns a...
Definition: Object.cpp:436
std::string GetCategoryAndName() const
Builds a string from an Object's category and name to allow the user to identify an Object's type.
Definition: Object.h:2158
Util::SynchronizedPointer< const ParamsType > ParamsConstTypeSyncPtrType
Alias for the return type of Object::GetParams() const. Parameters wrapped into Util::SynchronizedPoi...
Definition: Object.h:1989
Util::Warning Warning
Last warning which occurred within this Object instance. (Logical const-ness: see above....
Definition: Object.h:2305
virtual void EnsureReadyStateChild(bool IsAutomaticStartup)=0
Ensures that this Object instance is ready by possibly starting its worker thread or by opening conne...
void LogWarning() const
Writes Object::Warning to the event log returned by Util::EventLog().
Definition: Object.cpp:480
virtual ~Object()=0
Definition: Object.cpp:368
const std::thread::id OwnerThreadID
Thread id of the thread which has constructed (and owns) this Object instance.
Definition: Object.h:2302
virtual void ResetImpl(dispatch_tag< Object >)=0
Refer to DynExp::Object::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of every de...
void BlockIfUnused(const std::chrono::milliseconds Timeout=Util::ILockable::DefaultTimeout)
Blocks this Object instance setting Object::IsBlocked to true. Refer to Object::IsBlocked for the con...
Definition: Object.cpp:421
bool IsUnusedUnsafe()
Returns whether this Object instance is used by other instances (not thread-safe).
Definition: Object.h:2273
bool IsUnused(const std::chrono::milliseconds Timeout=Util::ILockable::DefaultTimeout) const
Returns whether this Object instance is used by other instances.
Definition: Object.h:2223
void ClearWarning() const
Resets Object::Warning.
Definition: Object.h:2190
void Reset()
Resets this Object instance (including all its derived classes) by calling ResetImpl()....
Definition: Object.cpp:403
const ParamsBasePtrType Params
Pointer to the parameter class instance belonging to this Object instance.
Definition: Object.h:2303
static constexpr std::chrono::milliseconds GetParamsTimeoutDefault
Default timeout used by Object::GetParams() to lock the mutex of the parameter instance assigned to t...
Definition: Object.h:2010
ParamsTypeSyncPtrType GetNonConstParams(const std::chrono::milliseconds Timeout=GetParamsTimeoutDefault) const
Allows derived Objects to edit their own parameters - even in const task functions (for instruments) ...
Definition: Object.cpp:475
ObjectUserList UserList
List of Object instances making use of this Object instance. Other Object instances making use of thi...
Definition: Object.h:2312
bool IsReady() const
Returns wheter this Object instance is ready (e.g. it is running or connected to a hardware device) a...
Definition: Object.h:2211
bool IsBlocked
This flag indicates whether this Object instance is blocked in order to be destroyed subsequently....
Definition: Object.h:2320
void EnsureReadyState(bool IsAutomaticStartup)
Ensures that this Object instance is ready by possibly starting its worker thread or by opening conne...
Definition: Object.cpp:446
std::exception_ptr GetException(const std::chrono::milliseconds Timeout=Util::ILockable::DefaultTimeout) const
Returns a pointer to the exception which has caused this Object instance to fail.
Definition: Object.h:2204
void DeregisterAllUnsafe()
Deregisters all users and notifies them that they need to check the states of their used linked objec...
Definition: Object.h:2265
bool IsSharedUsageEnabled(const std::chrono::milliseconds Timeout=GetParamsTimeoutDefault) const
Returns whether shared usage has been enabled for this Object instance. Refer to ParamsBase::UsageTyp...
Definition: Object.h:2136
auto GetObjectName(const std::chrono::milliseconds Timeout=GetParamsTimeoutDefault) const
Returns the name of this Object instance.
Definition: Object.h:2128
Util::SynchronizedPointer< ParamsType > ParamsTypeSyncPtrType
Alias for the return type of Object::GetParams(). Parameters wrapped into Util::SynchronizedPointer c...
Definition: Object.h:1983
static std::string CategoryAndNameToStr(const std::string &Category, const std::string &Name)
Builds a string from an Object's category and name to allow the user to identify an Object's type.
Definition: Object.cpp:350
auto LockUserList(const std::chrono::milliseconds Timeout=Util::ILockable::DefaultTimeout)
Locks the user list for thread-safe manipulation.
Definition: Object.h:2264
void EnsureCallFromOwningThread() const
Asserts that the call to this function is performed from the thread which constructed this Object ins...
Definition: Object.cpp:468
Refer to ParamsBase::dispatch_tag.
Definition: Object.h:2018
Makes sure the object link parameters of the associated ParamsBase instance are in a ready state by p...
Definition: Object.h:1589
bool operator()()
Performs the initialization stepwise. This functions is to be called as long as it returns true....
Definition: Object.cpp:179
Abstract base class for a single object parameter. Parameters derived from this class are automatical...
Definition: Object.h:378
ParamBase(ParamsBase &Owner, std::string ParamName, std::string_view ParamTitle, std::string_view ParamDescription, bool NeedsResetToApplyChange)
Base constructor of any parameter to be used if a parameter should be displayed in a settings dialog ...
Definition: Object.cpp:113
void FromXMLNode(const QDomElement &XMLElement)
Restores this parameter's value from the given Qt dom element (describing an XML node)
Definition: Object.cpp:145
bool Validate()
Checks whether a valid value is assigned to this parameter. This function is not const since it is al...
Definition: Object.cpp:164
ParamsBase & Owner
Owner of this parameter. Owner always lives longer than this object.
Definition: Object.h:498
QDomElement ToXMLNode(QDomDocument &Document) const
Converts this parameter to a Qt dom element (describing an XML node containing this parameter's name ...
Definition: Object.cpp:137
Abstract base class for object parameter classes. Each class derived from class Object must be accomp...
Definition: Object.h:326
virtual const char * GetParamClassTag() const noexcept
This function is intended to be overridden once in each derived class returning the name of the respe...
Definition: Object.h:1643
QDomElement ConfigToXML(QDomDocument &Document) const
Creates an XML node with a tag name as determined by GetParamClassTag() containing all parameters bel...
Definition: Object.cpp:202
bool ConfigureUsageType() const noexcept
Determines whether the Usage parameter should be configurable in the settings dialog....
Definition: Object.h:1733
Param< UsageType > Usage
Determines whether an object can be used by only one other ("unique") or by multiple other ("shared")...
Definition: Object.h:1725
virtual void ConfigureParamsImpl(dispatch_tag< ParamsBase >)
Called by DynExp::ParamsBase::ConfigureParams() as a starting point for the tag dispatch mechanism to...
Definition: Object.h:1762
bool Validate() const
Refer to ParamBase::Validate().
Definition: Object.cpp:271
void ConfigureParams()
Called by ConfigFromDialog() to apply changes to parameters owned by this parameter class instance be...
Definition: Object.cpp:297
void ConfigFromXML(const QDomElement &XMLElement) const
Retrieves all parameters belonging to this ParamsBase instance from an XML node with a tag name as de...
Definition: Object.cpp:222
OwnedParamsType OwnedParams
List of all parameters owned by this parameter class instance.
Definition: Object.h:1712
static void DisableUserEditable(ParamBase &Param) noexcept
Sets the UserEditable property of the parameter Param to false. Refer to ParamBase::UserEditable.
Definition: Object.cpp:292
const ItemIDType ID
ID of the Object this parameter class instance belongs to.
Definition: Object.h:1779
const auto & GetCore() const noexcept
Returns a reference to DynExp's core.
Definition: Object.h:1677
void ConfigFromDialog(ParamsConfigDialog &Dialog)
Adds all parameters belonging to this ParamsBase instance to a settings dialog to let the user config...
Definition: Object.cpp:260
virtual ~ParamsBase()=0
Definition: Object.cpp:198
std::filesystem::path ToAbsolutePath(const std::filesystem::path &Path) const
Transforms the path Path into an absolute path relative to ProjectParams::ProjectFilename.
Definition: Object.cpp:305
const DynExpCore & Core
Reference to DynExp's core.
Definition: Object.h:1780
static Util::TextValueListType< UsageType > AvlblUsageTypeStrList()
Maps description strings to the ParamsBase::UsageType enum's items.
Definition: Object.cpp:282
Tag for function dispatching mechanism within this class used when derived classes are not intended t...
Definition: Object.h:349
Defines data for a thread belonging to a RunnableObject instance. This data is only accessed by the R...
Definition: Object.h:3505
RunnableInstance(RunnableObject &Owner, std::promise< void > &&ThreadExitedPromise)
Constructs a non-empty RunnableInstance instance.
Definition: Object.cpp:753
LinkedObjectWrapperBase::ListType OwnedLinkedObjectWrappers
List of all LinkedObjectWrapper instances owned by this RunnableInstance instance (thus belonging to ...
Definition: Object.h:3726
void SetThreadExited()
Signals that Owner's thread has exited. Refer to RunnableObject::OnThreadHasExited().
Definition: Object.cpp:825
std::string GetNotReadyObjectNamesString() const
Finds all linked Object instances Owner makes use of which are not in a ready state and builds a stri...
Definition: Object.cpp:815
bool CareAboutWrappers()
Unregisters owned LinkedObjectWrapper instances from their destiny resources in case of the respectiv...
Definition: Object.cpp:776
const RunnableObject & Owner
RunnableObject instance which operates on this RunnableInstance (by its thread). The RunnableObject i...
Definition: Object.h:3705
bool Empty
Set to true if it was moved from this instance to indicate that ThreadExitedPromise has no shared sta...
Definition: Object.h:3718
std::promise< void > ThreadExitedPromise
Signals the RunnableObject instance owning the thread that its thread has terminated....
Definition: Object.h:3712
const auto & GetOwner() const noexcept
Returns Owner.
Definition: Object.h:3524
static Util::TextValueListType< StartupType > AvlblStartupTypeStrList()
Maps description strings to the RunnableObjectParams::StartupType enum's items.
Definition: Object.cpp:489
void ConfigureParamsImpl(dispatch_tag< ParamsBase >) override final
Called by DynExp::ParamsBase::ConfigureParams() as a starting point for the tag dispatch mechanism to...
Definition: Object.cpp:500
virtual ~RunnableObjectParams()=0
Definition: Object.cpp:485
Exception type thrown by TerminateImpl() if the RunnableObject cannot be terminated for being used by...
Definition: Object.h:2454
std::string GetErrorMessage() const
Genereates a user-readable error message containing the content of UserNames.
Definition: Object.cpp:512
Defines an Object which possesses a thread it runs in. The RunnableObject can be started and stopped ...
Definition: Object.h:2426
std::atomic< bool > Running
Indicates whether the RunnableObject instance is running.
Definition: Object.h:2684
void ResetImpl(dispatch_tag< Object >) override final
Refer to DynExp::Object::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of every de...
Definition: Object.cpp:668
bool IsCallFromRunnableThread() const
Checks whether Thread's id matches the id of the calling thread. This is thread-safe if the function ...
Definition: Object.cpp:656
std::promise< void > MakeThreadExitedPromise()
Helper function to be used by overridden RunChild() functions in derived classes to (re)initialize th...
Definition: Object.cpp:643
void Init()
Initializes member variables in case of a reset.
Definition: Object.cpp:634
bool Run(QWidget *ParentWidget=nullptr)
Starts the RunnableObject instance's thread and ensures that all Object instances linked to this inst...
Definition: Object.cpp:550
std::future< void > ThreadExitedSignal
Future which signals that Thread has terminated. Refer to OnThreadHasExited().
Definition: Object.h:2683
virtual void NotifyChild()
Notify derived classes that some state has changed (e.g. the termination of Thread is requested) and ...
Definition: Object.h:2629
virtual void RunChild()=0
Refer to Run().
virtual std::unique_ptr< BusyDialog > MakeStartupBusyDialogChild(QWidget *ParentWidget) const
Override to make this function return a pointer to a BusyDialog instance. Refer to Run().
Definition: Object.h:2646
RunnableObject(const std::thread::id OwnerThreadID, ParamsBasePtrType &&Params)
Constructs an Object instance.
Definition: Object.cpp:518
void TerminateUnsafe(bool Force, const std::chrono::milliseconds Timeout=TerminateTimeoutDefault)
Notifies the RunnableObject instance's thread to terminate and waits until it has ended....
Definition: Object.cpp:695
virtual ~RunnableObject()=0
Definition: Object.cpp:524
std::thread Thread
The RunnableObject instance's thread.
Definition: Object.h:2682
bool RunIfRunAutomatic()
Calls Run() if RunnableObjectParams::Startup is set to RunnableObjectParams::Automatic.
Definition: Object.cpp:594
std::atomic< RunnableObjectParams::StartupType > Startup
Reflects the value of RunnableObjectParams::Startup. This variable is only updated when Run() is call...
Definition: Object.h:2680
void TerminateImpl(bool Force, const std::chrono::milliseconds Timeout=TerminateTimeoutDefault)
Notifies the RunnableObject instance's thread to terminate and waits until it has ended....
Definition: Object.cpp:681
std::atomic< bool > Paused
Indicates whether the RunnableObject instance is paused.
Definition: Object.h:2685
std::atomic< bool > ShouldExit
Indicates whether this RunnableObject instance's thread should terminate.
Definition: Object.h:2693
void StoreThread(std::thread &&Thread) noexcept
Stores a thread constructed by a derived class overriding RunChild() in Thread taking ownership of th...
Definition: Object.cpp:651
Util::Warning ReasonWhyPaused
Holds information about why the RunnableObject instance is paused.
Definition: Object.h:2686
void OnThreadHasExited() noexcept
This function is called when the RunnableObject instance's thread terminates. The thread receives a R...
Definition: Object.cpp:713
std::atomic< bool > LinkedObjStateCheckRequested
Indicates whether the RunnableInstance instance belonging to this RunnableObject instance's thread sh...
Definition: Object.h:2700
void ClearReasonWhyPaused()
Removes the reason why this RunnableObject instance has been paused (since it is resumed).
Definition: Object.h:2610
void SetReasonWhyPaused(std::string Description)
Sets the reason why this RunnableObject instance has been paused.
Definition: Object.h:2599
void EnsureCallFromRunnableThread() const
Asserts that the call to this function is performed from the RunnableObject instance's thread by call...
Definition: Object.cpp:661
void EnsureReadyStateChild(bool IsAutomaticStartup) override final
Ensures that this Object instance is ready by possibly starting its worker thread or by opening conne...
Definition: Object.cpp:676
void SetPaused(bool Pause, std::string Description="")
Pauses or resumes a RunnableObject instance. Its thread stays running, but the instance does not perf...
Definition: Object.cpp:624
bool IsRunning() const noexcept
Returns Running.
Definition: Object.h:2550
bool RunIfRunOnCreation()
Calls Run() if RunnableObjectParams::Startup is set to RunnableObjectParams::OnCreation.
Definition: Object.cpp:607
void Terminate(bool Force=false, const std::chrono::milliseconds Timeout=TerminateTimeoutDefault)
Notifies the RunnableObject instance's thread to terminate and waits until it has ended....
Definition: Object.cpp:617
virtual void TerminateChild(const std::chrono::milliseconds Timeout)
Signals derived classes that terminating the RunnableObject instance's thread is about to be requeste...
Definition: Object.h:2638
Defines the configuration dialog. The dialog must be displayed by calling ParamsConfigDialog::Display...
Definition: ParamsConfig.h:72
void Log(const std::string &Message, const ErrorType Type=ErrorType::Info, const size_t Line=0, const std::string &Function="", const std::string &File="", const int ErrorCode=0, const std::stacktrace &Trace={}) noexcept
Logs an event from information specified manually.
Definition: Util.cpp:309
DynExp exceptions are derived from this class. It contains basic information about the cause of the e...
Definition: Exception.h:51
std::unique_lock< MutexType > LockType
Definition: Util.h:66
An invalid argument like a null pointer has been passed to a function.
Definition: Exception.h:137
Thrown when a function call is not allowed to a specific thread in a multi-threading context.
Definition: Exception.h:175
An operation cannot be performed currently since the related object is in an invalid state like an er...
Definition: Exception.h:150
Thrown when some operation or feature is temporarily or permanently not available.
Definition: Exception.h:286
Thrown when a requested ressource does not exist.
Definition: Exception.h:236
Thrown when a numeric operation would result in an overflow (e.g. due to incompatible data types)
Definition: Exception.h:199
Pointer to lock a class derived from ISynchronizedPointerLockable for synchronizing between threads....
Definition: Util.h:170
Thrown in a multi-threading context when an answer is expected from another thread an when the commun...
Definition: Exception.h:274
Thrown when an operation timed out before it could be completed, especially used for locking shared d...
Definition: Exception.h:261
Thrown when a numeric operation would result in an underflow (e.g. due to incompatible data types)
Definition: Exception.h:187
Class to store information about warnings in a thread-safe manner (deriving from ILockable)....
Definition: Util.h:966
void Reset()
Clears the warning data.
Definition: Util.cpp:273
DynExp's main namespace contains the implementation of DynExp including classes to manage resources (...
ParamsBasePtrType MakeParams(ItemIDType ID, const DynExpCore &Core)
Factory function to generate an Object's parameters.
Definition: Object.h:1818
std::vector< ItemIDType > ItemIDListType
Type of a list of IDs belonging to objects managed by DynExp.
Definition: Object.h:40
std::unique_ptr< ParamsBase > ParamsBasePtrType
Alias for a pointer to the parameter system base class ParamsBase.
Definition: Object.h:1807
size_t ItemIDType
ID type of objects/items managed by DynExp.
QDomElement GetSingleChildDOMElement(const QDomElement &Parent, const QString &ChildTagName)
Behaves like GetSingleChildDOMNode() but returns the node converted to a DOM element.
Definition: QtUtil.cpp:62
EventLogger & EventLog()
This function holds a static EventLogger instance and returns a reference to it. DynExp uses only one...
Definition: Util.cpp:509
std::vector< std::pair< TextType, ValueType > > TextValueListType
Type of a list containing key-value pairs where key is a text of type Util::TextType.
Definition: QtUtil.h:37
Accumulates include statements to provide a precompiled header.
Return type of ConfiguratorBase::UpdateConfigFromDialog() indicating the result of the configurator d...
Definition: Object.h:1889