DynExp
Highly flexible laboratory automation for dynamically changing experiments.
Loading...
Searching...
No Matches
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
7namespace 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
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 {
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
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
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 {
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
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
304
305 std::filesystem::path ParamsBase::ToAbsolutePath(const std::filesystem::path& Path) const
306 {
307 return GetCore().ToAbsolutePath(Path);
308 }
309
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 std::string Object::RemoveCategoryAndName(const std::string& ObjectDesc)
359 {
360 return std::regex_replace(ObjectDesc, std::regex("(\\([^()]*\\))"), "");
361 }
362
363 Object::Object(const std::thread::id OwnerThreadID, ParamsBasePtrType&& Params)
364 : LinkedObjectWrapperOnly(*this), OwnerThreadID(OwnerThreadID), Params(std::move(Params))
365 {
366 if (OwnerThreadID == std::thread::id())
367 throw Util::InvalidArgException("OwnerThreadID is not a valid thread identifier.");
368
369 if (!this->Params)
370 throw Util::InvalidArgException("Params cannot be nullptr.");
371 }
372
374 {
375#ifdef DYNEXP_DEBUG
376 Util::EventLog().Log("Item \"" + GetObjectName() + "\" is being removed.");
377#endif // DYNEXP_DEBUG
378 }
379
380 void Object::LinkedObjectWrapperOnlyType::RegisterUser(const Object& User, const std::chrono::milliseconds Timeout) const
381 {
382 // Longer timeout in case a module is started which itself starts an instrument (empiric value...)
383 // since the instrument might have locked its Params while starting up.
384 // If longer timeout is not allowed, this might throw Util::TimeoutException.
385 auto IsSharedUsage = Parent.IsSharedUsageEnabled(std::chrono::milliseconds(1000));
386
387 // Now, race condition between Object::IsReady() and Object::BlockIfUnused() is avoided.
388 auto lock = Parent.UserList.AcquireLock(Timeout);
389
390 // Just a check for the moment, no guarantee, that the required object stays in a healthy state...
391 if (!Parent.IsReady())
392 throw Util::InvalidStateException("The required item is in an invalid state or in an error state.");
393
394 if (!IsSharedUsage && !Parent.IsUnusedUnsafe())
396 "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."
397 + std::string("\n\n") + Parent.UserList.GetUserNamesStringUnsafe(),
399
400 Parent.UserList.Register(User, std::move(lock));
401 }
402
403 void Object::LinkedObjectWrapperOnlyType::DeregisterUser(const Object& User, const std::chrono::milliseconds Timeout) const
404 {
405 Parent.UserList.Deregister(User, Timeout);
406 }
407
409 {
411
412 // Now, objects trying to make use of this object cannot register themselves here anymore.
413 // They have to wait until reset is done.
414 auto lock = UserList.AcquireLock();
415
416 if (!IsUnusedUnsafe())
418 "This item is currently being used by at least another item. Stop and reset these items before resetting this item."
419 + std::string("\n\n") + UserList.GetUserNamesStringUnsafe());
420
421 ClearWarning();
422
424 }
425
426 void Object::BlockIfUnused(const std::chrono::milliseconds Timeout)
427 {
429
430 // Now, race condition between Object::IsReady() and Object::BlockIfUnused() is avoided.
431 auto lock = UserList.AcquireLock(Timeout);
432
433 if (!IsUnusedUnsafe())
435 "This item is currently being used by at least another item. Stop and reset these items before deleting this item."
436 + std::string("\n\n") + UserList.GetUserNamesStringUnsafe());
437
438 IsBlocked = true;
439 }
440
441 Object::ParamsConstTypeSyncPtrType Object::GetParams(const std::chrono::milliseconds Timeout) const
442 {
443 return ParamsConstTypeSyncPtrType(Params.get(), Timeout);
444 }
445
446 Object::ParamsTypeSyncPtrType Object::GetParams(const std::chrono::milliseconds Timeout)
447 {
448 return ParamsTypeSyncPtrType(Params.get(), Timeout);
449 }
450
451 void Object::EnsureReadyState(bool IsAutomaticStartup)
452 {
453 // EnsureCallFromOwningThread(); does not work here because hardware adapters are connected asynchronously
454 // from another thread in DynExpManager::OnRunProject().
455
456 EnsureReadyStateChild(IsAutomaticStartup);
457 }
458
459 void Object::SetWarning(std::string Description, int ErrorCode) const
460 {
461 Warning = Util::Warning(std::move(Description), ErrorCode);
462
463 LogWarning();
464 }
465
467 {
468 Warning = e;
469
470 LogWarning();
471 }
472
474 {
475 if (std::this_thread::get_id() != OwnerThreadID)
477 "This function must be called from the thread managing this object. A call from another instrument or module thread is not supported.");
478 }
479
480 Object::ParamsTypeSyncPtrType Object::GetNonConstParams(const std::chrono::milliseconds Timeout) const
481 {
482 return ParamsTypeSyncPtrType(Params.get(), Timeout);
483 }
484
486 {
488 }
489
493
495 {
497 { "Start item as soon as it is created", RunnableObjectParams::StartupType::OnCreation },
498 { "Start item as soon as it is required by another item", RunnableObjectParams::StartupType::Automatic },
499 { "Start item only manually", RunnableObjectParams::StartupType::Manual }
500 };
501
502 return List;
503 }
504
506 {
507 if (!ConfigureStartupType())
508 DisableUserEditable(Startup);
509
510 ConfigureParamsImpl(dispatch_tag<RunnableObjectParams>());
511 }
512
516
518 {
519 return "This item is currently being used by at least another item. Stop and reset these items before stopping this item."
520 + std::string("\n\n") + GetUserNames().data();
521 }
522
524 : Object(OwnerThreadID, std::move(Params)), RunnableInstanceOnly(*this)
525 {
526 Init();
527 }
528
530 {
531 try
532 {
533 // Better call terminate before destruction manually to handle errors.
534 TerminateImpl(false);
535 }
536 catch (const Util::TimeoutException& e)
537 {
538 Util::EventLog().Log(e);
539 Util::EventLog().Log("Could not terminate thread in the runnable's destructor. Timeout occurred. Execution cannot continue.",
541
542 std::terminate();
543 }
544 catch (const Util::NotAvailableException& e)
545 {
546 // Should never happen since modules are destroyed first in DynExpCore.
547 Util::EventLog().Log(e);
548 Util::EventLog().Log("Could not terminate thread in the runnable's destructor. The runnable is still in use. Execution cannot continue.",
550
551 std::terminate();
552 }
553 }
554
555 bool RunnableObject::Run(QWidget* ParentWidget)
556 {
558
559 if (GetException())
561 "A runnable is in an error state. It requires to be reset in order to transition into a ready state.");
562
563 auto StartupDialog = MakeStartupBusyDialogChild(ParentWidget);
564 int Result = QDialog::Accepted;
565 if (StartupDialog)
566 {
567 auto Params = GetParams();
568 ParamsBase::LinkParamStarter LinkParamStarter(*Params);
569 StartupDialog->SetCheckFinishedFunction(LinkParamStarter);
570
571 // StartupDialog->exec() blocks and starts new event loop for the modal dialog (in the same thread).
572 Result = StartupDialog->exec();
573 }
574
575 if (StartupDialog && Result != QDialog::Accepted)
576 {
577 if (StartupDialog->GetException())
578 std::rethrow_exception(StartupDialog->GetException());
579
580 return false;
581 }
582 if (IsRunning())
583 return false;
584
585 // Always call Reset() before starting to allow using Reset() for initialization.
586 // 'if (IsExiting())' could in principle be used here to determine whether the
587 // RunnableObject is not being started for the first time.
588 Reset();
589
590 auto Params = dynamic_Params_cast<RunnableObject>(GetParams());
591 Startup = Params->Startup;
592
593 RunChild();
594 Running = true;
595
596 return true;
597 }
598
600 {
601 auto Params = dynamic_Params_cast<RunnableObject>(GetParams());
602
604 return Run();
605 else if (!IsRunning())
606 throw Util::NotAvailableException("The required item " + Params->ObjectName.Get() + " (" + GetCategoryAndName() +
607 ") cannot be started since automatic startup has been disabled for this item.", Util::ErrorType::Error);
608
609 return false;
610 }
611
613 {
614 auto Params = dynamic_Params_cast<RunnableObject>(GetParams());
615
617 return Run();
618
619 return false;
620 }
621
622 void RunnableObject::Terminate(bool Force, const std::chrono::milliseconds Timeout)
623 {
625
626 TerminateImpl(Force, Timeout);
627 }
628
629 void RunnableObject::SetPaused(bool Pause, std::string Description)
630 {
631 Paused = Pause;
632
633 if (Pause)
634 SetReasonWhyPaused(std::move(Description));
635 else
637 }
638
640 {
641 Running = false;
642 Paused = false;
644 ShouldExit = false;
646 }
647
649 {
650 std::promise<void> ThreadExitedPromise;
651 ThreadExitedSignal = ThreadExitedPromise.get_future();
652
653 return ThreadExitedPromise;
654 }
655
656 void RunnableObject::MakeThread(ThreadFuncType ThreadFunc, std::unique_ptr<RunnableInstance>&& InstancePtr)
657 {
658 Util::OnDestruction ThreadStartFunc(InstancePtr->RunnableObjectOnly, &RunnableInstance::RunnableObjectOnlyType::SetThreadMayStart);
659
660 Thread = std::thread(ThreadFunc, std::move(InstancePtr), this);
661 }
662
664 {
665 return std::this_thread::get_id() == Thread.get_id();
666 }
667
669 {
672 "This function must be called from this runnable's thread. A call from another thread is not supported.");
673 }
674
682
683 void RunnableObject::EnsureReadyStateChild(bool IsAutomaticStartup)
684 {
685 IsAutomaticStartup ? RunIfRunAutomatic() : RunIfRunOnCreation();
686 }
687
688 void RunnableObject::TerminateImpl(bool Force, const std::chrono::milliseconds Timeout)
689 {
690 // Now, objects trying to make use of this object cannot register themselves here anymore.
691 auto lock = LockUserList();
692 auto IsUnused = IsUnusedUnsafe();
693
694 if (!Force && !IsUnused)
695 throw NotUnusedException(*this);
696
697 if (!IsUnused)
699 TerminateUnsafe(Force, Timeout);
700 }
701
702 void RunnableObject::TerminateUnsafe(bool Force, const std::chrono::milliseconds Timeout)
703 {
704 if (!Thread.joinable())
705 return;
706
707 TerminateChild(Timeout);
708
709 ShouldExit = true;
710 NotifyChild();
711 if (ThreadExitedSignal.wait_for(Timeout) != std::future_status::ready)
713
714 Thread.join();
715 Thread = std::thread();
716 Running = false;
717 Paused = false;
718 }
719
721 {
722 // Just indicate status changes. All the clean up is performed in the main thread when
723 // 1) Terminate() is called (calls TerminateUnsafe(), Thread is still joinable)
724 // 2) Reset() is called (calls TerminateUnsafe())
725 // 3) Run() is called (it calls Reset())
726 // There is no race condition since TerminateChild() also sets Running to false and
727 // Running is not read in between (IsRunning() is not called).
728 ShouldExit = true;
729 Running = false;
730 Paused = false;
731
732 // This is necessary if the RunnableObject is not terminated regularly but by an error.
734 }
735
739
741 {
742 return Owner.GetOwner();
743 }
744
748
755
759
760 RunnableInstance::RunnableInstance(RunnableObject& Owner, std::promise<void>&& ThreadExitedPromise)
762 RunnableObjectOnly(*this), Owner(Owner),
763 ThreadExitedPromise(std::move(ThreadExitedPromise))
764 {
765 }
766
767 // Not noexcept since move-constructor of std::list is not noexcept.
769 : ParamsGetter(Other.ParamsGetter),
770 RunnableObjectOnly(*this), Owner(Other.Owner),
771 ThreadExitedPromise(std::move(Other.ThreadExitedPromise)),
772 OwnedLinkedObjectWrappers(std::move(Other.OwnedLinkedObjectWrappers))
773 {
774 Other.Empty = true;
775 }
776
778 {
780
781 std::for_each(OwnedLinkedObjectWrappers.cbegin(), OwnedLinkedObjectWrappers.cend(), [](const auto& i) {
782 i.OwnedLinkedObjectWrapperContainer.Reset();
783 });
784 }
785
787 {
788 while (!ThreadMayStart)
789 std::this_thread::yield();
790 }
791
793 {
794 bool AnyDestinyNotReady = false;
795
796 if (GetOwner().RunnableInstanceOnly.IsLinkedObjStateCheckRequested())
797 {
798 GetOwner().RunnableInstanceOnly.ResetLinkedObjStateCheckRequested();
799
800 for (auto& Wrapper : OwnedLinkedObjectWrappers)
801 Wrapper.OwnedLinkedObjectWrapperContainer.CheckIfReady();
802 }
803
804 for (auto& Wrapper : OwnedLinkedObjectWrappers)
805 {
806 if (Wrapper.OwnedLinkedObjectWrapperContainer.GetState() == LinkedObjectWrapperContainerBase::LinkedObjectStateType::NotReady)
807 {
808 AnyDestinyNotReady = true;
809
810 if (Wrapper.OwnedLinkedObjectWrapperPtr->IsRegistered())
811 Wrapper.OwnedLinkedObjectWrapperPtr->Deregister(std::chrono::milliseconds(100));
812 else
813 {
814 try
815 {
816 Wrapper.OwnedLinkedObjectWrapperPtr->Register(ObjectLinkBase::LockObjectTimeoutDefault);
817 Wrapper.OwnedLinkedObjectWrapperContainer.LinkedObjectState = LinkedObjectWrapperContainerBase::LinkedObjectStateType::Ready;
818 }
819 catch (...)
820 {
821 // Registering failed because underlying object is still in an error state.
822 // Swallow the exception and try again next time this function is called.
823 }
824 }
825 }
826 }
827
828 return !AnyDestinyNotReady;
829 }
830
832 {
833 std::string Names("Linked items not being in a ready state:");
834 for (auto& Wrapper : OwnedLinkedObjectWrappers)
835 if (Wrapper.OwnedLinkedObjectWrapperContainer.GetState() == LinkedObjectWrapperContainerBase::LinkedObjectStateType::NotReady)
836 Names += "\n- " + Wrapper.OwnedLinkedObjectWrapperContainer.GetLinkedObjectDesc();
837
838 return Names;
839 }
840
842 {
843 if (!Empty)
844 {
845 // ThreadExitedPromise.set_value_at_thread_exit(); does not work, because
846 // ThreadExitedSignal.wait_for(Timeout) in InstrumentBase::Terminate() would not
847 // return in case of timeout since the value is already stored.
848 ThreadExitedPromise.set_value();
849
850 GetOwner().RunnableInstanceOnly.OnThreadHasExited();
851 }
852 }
853}
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:740
const RunnableInstance & Owner
Instance of class RunnableInstance managing the wrapper.
Definition Object.h:2825
void Reset() noexcept
Removes any linked LinkedObjectWrapper and updates LinkedObjectState.
Definition Object.cpp:749
LinkedObjectStateType LinkedObjectState
Stores the current state of this LinkedObjectWrapperContainerBase instance. Refer to LinkedObjectStat...
Definition Object.h:3133
virtual void ResetChild() noexcept=0
Removes any linked LinkedObjectWrapper and updates LinkedObjectState.
virtual ~ObjectLinkBase()=0
Definition Object.cpp:756
static constexpr std::chrono::milliseconds LockObjectTimeoutDefault
Default timeout used by classes ObjectLinkt and RunnableInstance to be passed to LinkedObjectWrapper:...
Definition Object.h:3375
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:403
Object & Parent
Owning Object instance.
Definition Object.h:2076
void RegisterUser(const Object &User, const std::chrono::milliseconds Timeout) const
Registers a user in a thread-safe way.
Definition Object.cpp:380
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:363
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:459
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:441
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:2166
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:2313
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:485
virtual ~Object()=0
Definition Object.cpp:373
const std::thread::id OwnerThreadID
Thread id of the thread which has constructed (and owns) this Object instance.
Definition Object.h:2310
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:426
bool IsUnusedUnsafe()
Returns whether this Object instance is used by other instances (not thread-safe).
Definition Object.h:2281
bool IsUnused(const std::chrono::milliseconds Timeout=Util::ILockable::DefaultTimeout) const
Returns whether this Object instance is used by other instances.
Definition Object.h:2231
void ClearWarning() const
Resets Object::Warning.
Definition Object.h:2198
void Reset()
Resets this Object instance (including all its derived classes) by calling ResetImpl()....
Definition Object.cpp:408
const ParamsBasePtrType Params
Pointer to the parameter class instance belonging to this Object instance.
Definition Object.h:2311
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:2018
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:480
ObjectUserList UserList
List of Object instances making use of this Object instance. Other Object instances making use of thi...
Definition Object.h:2320
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:2219
bool IsBlocked
This flag indicates whether this Object instance is blocked in order to be destroyed subsequently....
Definition Object.h:2328
void EnsureReadyState(bool IsAutomaticStartup)
Ensures that this Object instance is ready by possibly starting its worker thread or by opening conne...
Definition Object.cpp:451
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:2212
void DeregisterAllUnsafe()
Deregisters all users and notifies them that they need to check the states of their used linked objec...
Definition Object.h:2273
static std::string RemoveCategoryAndName(const std::string &ObjectDesc)
Removes the category and name part built by Object::CategoryAndNameToStr() from the string ObjectDesc...
Definition Object.cpp:358
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:2144
auto GetObjectName(const std::chrono::milliseconds Timeout=GetParamsTimeoutDefault) const
Returns the name of this Object instance.
Definition Object.h:2136
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:2272
void EnsureCallFromOwningThread() const
Asserts that the call to this function is performed from the thread which constructed this Object ins...
Definition Object.cpp:473
Refer to ParamsBase::dispatch_tag.
Definition Object.h:2026
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
const auto & GetCore() const noexcept
Returns a reference to DynExp's core.
Definition Object.h:1677
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
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
void SetThreadMayStart()
Sets RunnableInstance::ThreadMayStart to true, indicating that the thread Parent belongs to may start...
Definition Object.h:3541
Defines data for a thread belonging to a RunnableObject instance. This data is only accessed by the R...
Definition Object.h:3521
RunnableInstance(RunnableObject &Owner, std::promise< void > &&ThreadExitedPromise)
Constructs a non-empty RunnableInstance instance.
Definition Object.cpp:760
LinkedObjectWrapperBase::ListType OwnedLinkedObjectWrappers
List of all LinkedObjectWrapper instances owned by this RunnableInstance instance (thus belonging to ...
Definition Object.h:3782
void SetThreadExited()
Signals that Owner's thread has exited. Refer to RunnableObject::OnThreadHasExited().
Definition Object.cpp:841
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:831
void BlockUntilReadyToStart() const noexcept
Blocks until ThreadMayStart is set to true. Thread functions to be run by RunnableObject instances ar...
Definition Object.cpp:786
bool CareAboutWrappers()
Unregisters owned LinkedObjectWrapper instances from their destiny resources in case of the respectiv...
Definition Object.cpp:792
const RunnableObject & Owner
RunnableObject instance which operates on this RunnableInstance (by its thread). The RunnableObject i...
Definition Object.h:3754
bool Empty
Set to true if it was moved from this instance to indicate that ThreadExitedPromise has no shared sta...
Definition Object.h:3774
std::promise< void > ThreadExitedPromise
Signals the RunnableObject instance owning the thread that its thread has terminated....
Definition Object.h:3768
std::atomic< bool > ThreadMayStart
Indicates whether the thread this RunnableInstance instance belongs to may start working....
Definition Object.h:3761
const auto & GetOwner() const noexcept
Returns Owner.
Definition Object.h:3564
static Util::TextValueListType< StartupType > AvlblStartupTypeStrList()
Maps description strings to the RunnableObjectParams::StartupType enum's items.
Definition Object.cpp:494
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:505
virtual ~RunnableObjectParams()=0
Definition Object.cpp:490
Exception type thrown by TerminateImpl() if the RunnableObject cannot be terminated for being used by...
Definition Object.h:2462
std::string GetErrorMessage() const
Genereates a user-readable error message containing the content of UserNames.
Definition Object.cpp:517
Defines an Object which possesses a thread it runs in. The RunnableObject can be started and stopped ...
Definition Object.h:2434
std::atomic< bool > Running
Indicates whether the RunnableObject instance is running.
Definition Object.h:2700
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:675
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:663
std::promise< void > MakeThreadExitedPromise()
Helper function to be used by overridden RunChild() functions in derived classes to (re)initialize th...
Definition Object.cpp:648
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:2662
void MakeThread(ThreadFuncType ThreadFunc, std::unique_ptr< RunnableInstance > &&InstancePtr)
Creates and runs the thread of the RunnableObject instance. Call this function in the derived class o...
Definition Object.cpp:656
void Init()
Initializes member variables in case of a reset.
Definition Object.cpp:639
bool Run(QWidget *ParentWidget=nullptr)
Starts the RunnableObject instance's thread and ensures that all Object instances linked to this inst...
Definition Object.cpp:555
std::future< void > ThreadExitedSignal
Future which signals that Thread has terminated. Refer to OnThreadHasExited().
Definition Object.h:2699
virtual void NotifyChild()
Notify derived classes that some state has changed (e.g. the termination of Thread is requested) and ...
Definition Object.h:2645
virtual void RunChild()=0
Refer to Run().
RunnableObject(const std::thread::id OwnerThreadID, ParamsBasePtrType &&Params)
Constructs an Object instance.
Definition Object.cpp:523
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:702
virtual ~RunnableObject()=0
Definition Object.cpp:529
std::thread Thread
The RunnableObject instance's thread.
Definition Object.h:2698
bool RunIfRunAutomatic()
Calls Run() if RunnableObjectParams::Startup is set to RunnableObjectParams::Automatic.
Definition Object.cpp:599
std::atomic< RunnableObjectParams::StartupType > Startup
Reflects the value of RunnableObjectParams::Startup. This variable is only updated when Run() is call...
Definition Object.h:2696
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:688
std::atomic< bool > Paused
Indicates whether the RunnableObject instance is paused.
Definition Object.h:2701
std::atomic< bool > ShouldExit
Indicates whether this RunnableObject instance's thread should terminate.
Definition Object.h:2709
Util::Warning ReasonWhyPaused
Holds information about why the RunnableObject instance is paused.
Definition Object.h:2702
void OnThreadHasExited() noexcept
This function is called when the RunnableObject instance's thread terminates. The thread receives a R...
Definition Object.cpp:720
std::atomic< bool > LinkedObjStateCheckRequested
Indicates whether the RunnableInstance instance belonging to this RunnableObject instance's thread sh...
Definition Object.h:2716
std::function< int(std::unique_ptr< RunnableInstance > &&, RunnableObject *)> ThreadFuncType
Type of the thread function executed by RunnableObject instances.
Definition Object.h:2571
void ClearReasonWhyPaused()
Removes the reason why this RunnableObject instance has been paused (since it is resumed).
Definition Object.h:2626
void SetReasonWhyPaused(std::string Description)
Sets the reason why this RunnableObject instance has been paused.
Definition Object.h:2615
void EnsureCallFromRunnableThread() const
Asserts that the call to this function is performed from the RunnableObject instance's thread by call...
Definition Object.cpp:668
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:683
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:629
bool IsRunning() const noexcept
Returns Running.
Definition Object.h:2558
bool RunIfRunOnCreation()
Calls Run() if RunnableObjectParams::Startup is set to RunnableObjectParams::OnCreation.
Definition Object.cpp:612
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:622
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:2654
Defines the configuration dialog. The dialog must be displayed by calling ParamsConfigDialog::Display...
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:317
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:67
An invalid argument like a null pointer has been passed to a function.
Definition Exception.h:138
Thrown when a function call is not allowed to a specific thread in a multi-threading context.
Definition Exception.h:176
An operation cannot be performed currently since the related object is in an invalid state like an er...
Definition Exception.h:151
Thrown when some operation or feature is temporarily or permanently not available.
Definition Exception.h:287
Thrown when a requested ressource does not exist.
Definition Exception.h:237
Holds a CallableMemberWrapper and invokes its callable when being destroyed.
Definition Util.h:495
Thrown when a numeric operation would result in an overflow (e.g. due to incompatible data types)
Definition Exception.h:200
Pointer to lock a class derived from ISynchronizedPointerLockable for synchronizing between threads....
Definition Util.h:171
Thrown in a multi-threading context when an answer is expected from another thread an when the commun...
Definition Exception.h:275
Thrown when an operation timed out before it could be completed, especially used for locking shared d...
Definition Exception.h:262
Thrown when a numeric operation would result in an underflow (e.g. due to incompatible data types)
Definition Exception.h:188
Class to store information about warnings in a thread-safe manner (deriving from ILockable)....
Definition Util.h:1022
void Reset()
Clears the warning data.
Definition Util.cpp:281
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:517
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