diff --git a/CHANGES b/CHANGES index 13c76b5b..8c157a9b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +v.11.4.1 (21 November 2024) + - Fixed potential hang in multi-threaded circuit ticking. + - Fixed potential crash in multi-threaded circuit scanning. + v.11.4.0 (15 November 2024) - Updated fast_any submodule (incl. optimized "has value" detection). - Greatly optimized Tick() methods by removing unnecessary I/O resets. diff --git a/docs/Doxyfile b/docs/Doxyfile index e0dd676a..3225fc57 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -32,7 +32,7 @@ PROJECT_NAME = DSPatch # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = v.11.4.0 +PROJECT_NUMBER = v.11.4.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer diff --git a/docs/html/_circuit_8h_source.html b/docs/html/_circuit_8h_source.html index fefabf9a..3cd71e2b 100644 --- a/docs/html/_circuit_8h_source.html +++ b/docs/html/_circuit_8h_source.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
@@ -706,199 +706,191 @@
634{
635 PauseAutoTick();
636
-
637 if ( _threadCount == 0 && threadCount != 0 )
-
638 {
-
639 _circuitDirty = true;
-
640 }
-
641
-
642 _threadCount = threadCount;
-
643
-
644 // stop all threads
-
645 for ( auto& circuitThreads : _circuitThreadsParallel )
-
646 {
-
647 for ( auto& circuitThread : circuitThreads )
-
648 {
-
649 circuitThread.Stop();
-
650 }
-
651 }
-
652
-
653 // resize thread array
-
654 if ( _threadCount == 0 )
+
637 _threadCount = threadCount;
+
638
+
639 // stop all threads
+
640 for ( auto& circuitThreads : _circuitThreadsParallel )
+
641 {
+
642 for ( auto& circuitThread : circuitThreads )
+
643 {
+
644 circuitThread.Stop();
+
645 }
+
646 }
+
647
+
648 // resize thread array
+
649 if ( _threadCount == 0 )
+
650 {
+
651 _circuitThreadsParallel.resize( 0 );
+
652 SetBufferCount( _bufferCount );
+
653 }
+
654 else
655 {
-
656 _circuitThreadsParallel.resize( 0 );
-
657 SetBufferCount( _bufferCount );
-
658 }
-
659 else
-
660 {
-
661 _circuitThreadsParallel.resize( _bufferCount == 0 ? 1 : _bufferCount );
-
662 for ( auto& circuitThread : _circuitThreadsParallel )
-
663 {
-
664 circuitThread.resize( _threadCount );
-
665 }
-
666
-
667 // initialise and start all threads
-
668 int i = 0;
-
669 for ( auto& circuitThreads : _circuitThreadsParallel )
-
670 {
-
671 int j = 0;
-
672 for ( auto& circuitThread : circuitThreads )
-
673 {
-
674 circuitThread.Start( &_componentsParallel, i, j++, _threadCount );
-
675 }
-
676 ++i;
-
677 }
-
678 }
-
679
-
680 ResumeAutoTick();
-
681}
-
682
-
683// cppcheck-suppress unusedFunction
-
684inline int Circuit::GetThreadCount() const
-
685{
-
686 return _threadCount;
-
687}
-
688
-
689inline void Circuit::Tick()
-
690{
-
691 if ( _circuitDirty )
-
692 {
-
693 _Optimize();
-
694 }
-
695
-
696 // process in multiple threads if this circuit has threads
-
697 // =======================================================
-
698 if ( _threadCount != 0 )
-
699 {
-
700 auto& circuitThreads = _circuitThreadsParallel[_currentBuffer];
-
701
-
702 for ( auto& circuitThread : circuitThreads )
-
703 {
-
704 circuitThread.Sync();
-
705 }
-
706 for ( auto& circuitThread : circuitThreads )
-
707 {
-
708 circuitThread.Resume();
-
709 }
-
710 }
-
711 // process in a single thread if this circuit has no threads
-
712 // =========================================================
-
713 else if ( _bufferCount == 0 )
-
714 {
-
715 // tick all internal components
-
716 for ( auto component : _components )
-
717 {
-
718 component->Tick( 0 );
-
719 }
-
720
-
721 return;
-
722 }
-
723 else
+
656 _circuitThreadsParallel.resize( _bufferCount == 0 ? 1 : _bufferCount );
+
657 for ( auto& circuitThread : _circuitThreadsParallel )
+
658 {
+
659 circuitThread.resize( _threadCount );
+
660 }
+
661
+
662 // initialise and start all threads
+
663 int i = 0;
+
664 for ( auto& circuitThreads : _circuitThreadsParallel )
+
665 {
+
666 int j = 0;
+
667 for ( auto& circuitThread : circuitThreads )
+
668 {
+
669 circuitThread.Start( &_componentsParallel, i, j++, _threadCount );
+
670 }
+
671 ++i;
+
672 }
+
673 }
+
674
+
675 ResumeAutoTick();
+
676}
+
677
+
678// cppcheck-suppress unusedFunction
+
679inline int Circuit::GetThreadCount() const
+
680{
+
681 return _threadCount;
+
682}
+
683
+
684inline void Circuit::Tick()
+
685{
+
686 if ( _circuitDirty )
+
687 {
+
688 _Optimize();
+
689 }
+
690
+
691 // process in multiple threads if this circuit has threads
+
692 // =======================================================
+
693 if ( _threadCount != 0 )
+
694 {
+
695 auto& circuitThreads = _circuitThreadsParallel[_currentBuffer];
+
696
+
697 for ( auto& circuitThread : circuitThreads )
+
698 {
+
699 circuitThread.Sync();
+
700 }
+
701 for ( auto& circuitThread : circuitThreads )
+
702 {
+
703 circuitThread.Resume();
+
704 }
+
705 }
+
706 // process in a single thread if this circuit has no threads
+
707 // =========================================================
+
708 else if ( _bufferCount == 0 )
+
709 {
+
710 // tick all internal components
+
711 for ( auto component : _components )
+
712 {
+
713 component->Tick( 0 );
+
714 }
+
715
+
716 return;
+
717 }
+
718 else
+
719 {
+
720 _circuitThreads[_currentBuffer].SyncAndResume(); // sync and resume thread x
+
721 }
+
722
+
723 if ( _bufferCount != 0 && ++_currentBuffer == _bufferCount )
724 {
-
725 _circuitThreads[_currentBuffer].SyncAndResume(); // sync and resume thread x
+
725 _currentBuffer = 0;
726 }
-
727
-
728 if ( _bufferCount != 0 && ++_currentBuffer == _bufferCount )
-
729 {
-
730 _currentBuffer = 0;
-
731 }
-
732}
-
733
-
734inline void Circuit::Sync()
-
735{
-
736 // sync all threads
-
737 for ( auto& circuitThread : _circuitThreads )
-
738 {
-
739 circuitThread.Sync();
-
740 }
-
741 for ( auto& circuitThreads : _circuitThreadsParallel )
-
742 {
-
743 for ( auto& circuitThread : circuitThreads )
-
744 {
-
745 circuitThread.Sync();
-
746 }
-
747 }
+
727}
+
728
+
729inline void Circuit::Sync()
+
730{
+
731 // sync all threads
+
732 for ( auto& circuitThread : _circuitThreads )
+
733 {
+
734 circuitThread.Sync();
+
735 }
+
736 for ( auto& circuitThreads : _circuitThreadsParallel )
+
737 {
+
738 for ( auto& circuitThread : circuitThreads )
+
739 {
+
740 circuitThread.Sync();
+
741 }
+
742 }
+
743}
+
744
+
745inline void Circuit::StartAutoTick()
+
746{
+
747 _autoTickThread.Start( this );
748}
749
-
750inline void Circuit::StartAutoTick()
+
750inline void Circuit::StopAutoTick()
751{
-
752 _autoTickThread.Start( this );
-
753}
-
754
-
755inline void Circuit::StopAutoTick()
-
756{
-
757 _autoTickThread.Stop();
-
758 Sync();
-
759}
-
760
-
761inline void Circuit::PauseAutoTick()
-
762{
-
763 _autoTickThread.Pause();
-
764 Sync();
+
752 _autoTickThread.Stop();
+
753 Sync();
+
754}
+
755
+
756inline void Circuit::PauseAutoTick()
+
757{
+
758 _autoTickThread.Pause();
+
759 Sync();
+
760}
+
761
+
762inline void Circuit::ResumeAutoTick()
+
763{
+
764 _autoTickThread.Resume();
765}
766
-
767inline void Circuit::ResumeAutoTick()
+
767inline void Circuit::Optimize()
768{
-
769 _autoTickThread.Resume();
-
770}
-
771
-
772inline void Circuit::Optimize()
-
773{
-
774 if ( _circuitDirty )
-
775 {
-
776 PauseAutoTick();
-
777 _Optimize();
-
778 ResumeAutoTick();
-
779 }
-
780}
-
781
-
782inline void Circuit::_Optimize()
-
783{
-
784 // scan for optimal series order -> update _components
-
785 {
-
786 std::vector<DSPatch::Component*> orderedComponents;
-
787 orderedComponents.reserve( _components.size() );
-
788
-
789 for ( auto component : _components )
-
790 {
-
791 component->Scan( orderedComponents );
-
792 }
-
793 for ( auto component : _components )
-
794 {
-
795 component->EndScan();
-
796 }
-
797
-
798 _components = std::move( orderedComponents );
-
799 }
-
800
-
801 // scan for optimal parallel order -> update _componentsParallel
-
802 if ( _threadCount != 0 )
-
803 {
-
804 std::vector<std::vector<DSPatch::Component*>> componentsMap;
-
805 componentsMap.reserve( _components.size() );
-
806
-
807 int scanPosition;
-
808 for ( auto component : _components )
-
809 {
-
810 component->ScanParallel( componentsMap, scanPosition );
-
811 }
-
812 for ( auto component : _components )
-
813 {
-
814 component->EndScan();
-
815 }
+
769 if ( _circuitDirty )
+
770 {
+
771 PauseAutoTick();
+
772 _Optimize();
+
773 ResumeAutoTick();
+
774 }
+
775}
+
776
+
777inline void Circuit::_Optimize()
+
778{
+
779 // scan for optimal series order -> update _components
+
780 {
+
781 std::vector<DSPatch::Component*> orderedComponents;
+
782 orderedComponents.reserve( _components.size() );
+
783
+
784 for ( auto component : _components )
+
785 {
+
786 component->Scan( orderedComponents );
+
787 }
+
788 for ( auto component : _components )
+
789 {
+
790 component->EndScan();
+
791 }
+
792
+
793 _components = std::move( orderedComponents );
+
794 }
+
795
+
796 // scan for optimal parallel order -> update _componentsParallel
+
797 std::vector<std::vector<DSPatch::Component*>> componentsMap;
+
798 componentsMap.reserve( _components.size() );
+
799
+
800 int scanPosition;
+
801 for ( auto component : _components )
+
802 {
+
803 component->ScanParallel( componentsMap, scanPosition );
+
804 }
+
805 for ( auto component : _components )
+
806 {
+
807 component->EndScan();
+
808 }
+
809
+
810 _componentsParallel.clear();
+
811 _componentsParallel.reserve( _components.size() );
+
812 for ( auto& componentsMapEntry : componentsMap )
+
813 {
+
814 _componentsParallel.insert( _componentsParallel.end(), componentsMapEntry.begin(), componentsMapEntry.end() );
+
815 }
816
-
817 _componentsParallel.clear();
-
818 _componentsParallel.reserve( _components.size() );
-
819 for ( auto& componentsMapEntry : componentsMap )
-
820 {
-
821 _componentsParallel.insert( _componentsParallel.end(), componentsMapEntry.begin(), componentsMapEntry.end() );
-
822 }
-
823 }
-
824
-
825 // clear _circuitDirty flag
-
826 _circuitDirty = false;
-
827}
-
828
-
829} // namespace DSPatch
+
817 // clear _circuitDirty flag
+
818 _circuitDirty = false;
+
819}
+
820
+
821} // namespace DSPatch
Workspace for adding and routing components.
Definition Circuit.h:73
diff --git a/docs/html/_component_8h_source.html b/docs/html/_component_8h_source.html index 63275645..990abd8c 100644 --- a/docs/html/_component_8h_source.html +++ b/docs/html/_component_8h_source.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
@@ -566,10 +566,10 @@
491 }
492
493 // insert component at _scanPosition
-
494 if ( _scanPosition == (int)componentsMap.size() )
+
494 while ( (int)componentsMap.size() <= _scanPosition )
495 {
496 componentsMap.emplace_back( std::vector<DSPatch::Component*>{} );
-
497 componentsMap[_scanPosition].reserve( componentsMap.capacity() );
+
497 componentsMap.back().reserve( componentsMap.capacity() );
498 }
499 componentsMap[_scanPosition].emplace_back( this );
500}
@@ -639,7 +639,7 @@
564
565 if ( ref.total == 1 )
566 {
-
567 // there's only one reference, move the signal immediately
+
567 // there's only one reference, move the signal
568 toBus.MoveSignal( toInput, signal );
569 }
570 else if ( ++ref.count != ref.total )
@@ -666,47 +666,57 @@
591 if ( !signal.has_value() )
592 {
593 toBus.ClearValue( toInput );
-
594 return;
-
595 }
-
596
-
597 if ( ref.total == 1 )
-
598 {
-
599 // there's only one reference, move the signal immediately and return
-
600 toBus.MoveSignal( toInput, signal );
-
601 }
-
602 else if ( ++ref.count != ref.total )
-
603 {
-
604 // this is not the final reference, copy the signal
-
605 toBus.SetSignal( toInput, signal );
-
606
-
607 // wake next WaitAndClear()
-
608 ref.readyFlag.Set();
-
609 }
-
610 else
-
611 {
-
612 // this is the final reference, reset the counter, move the signal
-
613 ref.count = 0;
-
614 toBus.MoveSignal( toInput, signal );
-
615 }
-
616}
-
617
-
618inline void Component::_IncRefs( int output )
-
619{
-
620 for ( auto& ref : _refs )
+
594
+
595 if ( ref.total != 1 )
+
596 {
+
597 if ( ++ref.count != ref.total )
+
598 {
+
599 // this is not the final reference, wake next WaitAndClear()
+
600 ref.readyFlag.Set();
+
601 }
+
602 else
+
603 {
+
604 // this is the final reference, reset the counter
+
605 ref.count = 0;
+
606 }
+
607 }
+
608 }
+
609 else if ( ref.total == 1 )
+
610 {
+
611 // there's only one reference, move the signal
+
612 toBus.MoveSignal( toInput, signal );
+
613 }
+
614 else if ( ++ref.count != ref.total )
+
615 {
+
616 // this is not the final reference, copy the signal, wake next WaitAndClear()
+
617 toBus.SetSignal( toInput, signal );
+
618 ref.readyFlag.Set();
+
619 }
+
620 else
621 {
-
622 ++ref[output].total;
-
623 }
-
624}
-
625
-
626inline void Component::_DecRefs( int output )
-
627{
-
628 for ( auto& ref : _refs )
-
629 {
-
630 --ref[output].total;
-
631 }
-
632}
-
633
-
634} // namespace DSPatch
+
622 // this is the final reference, reset the counter, move the signal
+
623 ref.count = 0;
+
624 toBus.MoveSignal( toInput, signal );
+
625 }
+
626}
+
627
+
628inline void Component::_IncRefs( int output )
+
629{
+
630 for ( auto& ref : _refs )
+
631 {
+
632 ++ref[output].total;
+
633 }
+
634}
+
635
+
636inline void Component::_DecRefs( int output )
+
637{
+
638 for ( auto& ref : _refs )
+
639 {
+
640 --ref[output].total;
+
641 }
+
642}
+
643
+
644} // namespace DSPatch
Abstract base class for DSPatch components.
Definition Component.h:65
Signal container.
Definition SignalBus.h:53
diff --git a/docs/html/_d_s_patch_8h_source.html b/docs/html/_d_s_patch_8h_source.html index e43bf96b..fdc1baf5 100644 --- a/docs/html/_d_s_patch_8h_source.html +++ b/docs/html/_d_s_patch_8h_source.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
diff --git a/docs/html/_plugin_8h_source.html b/docs/html/_plugin_8h_source.html index 2da0e0d7..a3e45128 100644 --- a/docs/html/_plugin_8h_source.html +++ b/docs/html/_plugin_8h_source.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
diff --git a/docs/html/_signal_bus_8h_source.html b/docs/html/_signal_bus_8h_source.html index 398833d6..6e0d57b6 100644 --- a/docs/html/_signal_bus_8h_source.html +++ b/docs/html/_signal_bus_8h_source.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
diff --git a/docs/html/annotated.html b/docs/html/annotated.html index 0154a85f..69c68178 100644 --- a/docs/html/annotated.html +++ b/docs/html/annotated.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
diff --git a/docs/html/class_d_s_patch_1_1_circuit-members.html b/docs/html/class_d_s_patch_1_1_circuit-members.html index 4bd20dd9..b770a5fc 100644 --- a/docs/html/class_d_s_patch_1_1_circuit-members.html +++ b/docs/html/class_d_s_patch_1_1_circuit-members.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
diff --git a/docs/html/class_d_s_patch_1_1_circuit.html b/docs/html/class_d_s_patch_1_1_circuit.html index dee26bf1..a09c5960 100644 --- a/docs/html/class_d_s_patch_1_1_circuit.html +++ b/docs/html/class_d_s_patch_1_1_circuit.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
@@ -384,7 +384,7 @@

-

Definition at line 684 of file Circuit.h.

+

Definition at line 679 of file Circuit.h.

@@ -411,7 +411,7 @@

-

Definition at line 772 of file Circuit.h.

+

Definition at line 767 of file Circuit.h.

@@ -438,7 +438,7 @@

-

Definition at line 761 of file Circuit.h.

+

Definition at line 756 of file Circuit.h.

@@ -519,7 +519,7 @@

-

Definition at line 767 of file Circuit.h.

+

Definition at line 762 of file Circuit.h.

@@ -600,7 +600,7 @@

-

Definition at line 750 of file Circuit.h.

+

Definition at line 745 of file Circuit.h.

@@ -627,7 +627,7 @@

-

Definition at line 755 of file Circuit.h.

+

Definition at line 750 of file Circuit.h.

@@ -654,7 +654,7 @@

-

Definition at line 734 of file Circuit.h.

+

Definition at line 729 of file Circuit.h.

@@ -681,7 +681,7 @@

-

Definition at line 689 of file Circuit.h.

+

Definition at line 684 of file Circuit.h.

diff --git a/docs/html/class_d_s_patch_1_1_component-members.html b/docs/html/class_d_s_patch_1_1_component-members.html index 82ca7b22..ca216e3c 100644 --- a/docs/html/class_d_s_patch_1_1_component-members.html +++ b/docs/html/class_d_s_patch_1_1_component-members.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
diff --git a/docs/html/class_d_s_patch_1_1_component.html b/docs/html/class_d_s_patch_1_1_component.html index 94c56557..5e1619cd 100644 --- a/docs/html/class_d_s_patch_1_1_component.html +++ b/docs/html/class_d_s_patch_1_1_component.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
diff --git a/docs/html/class_d_s_patch_1_1_plugin-members.html b/docs/html/class_d_s_patch_1_1_plugin-members.html index dccce453..9123abee 100644 --- a/docs/html/class_d_s_patch_1_1_plugin-members.html +++ b/docs/html/class_d_s_patch_1_1_plugin-members.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
diff --git a/docs/html/class_d_s_patch_1_1_plugin.html b/docs/html/class_d_s_patch_1_1_plugin.html index dc45454b..3b77af27 100644 --- a/docs/html/class_d_s_patch_1_1_plugin.html +++ b/docs/html/class_d_s_patch_1_1_plugin.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
diff --git a/docs/html/class_d_s_patch_1_1_signal_bus-members.html b/docs/html/class_d_s_patch_1_1_signal_bus-members.html index 7b792609..80f4e81a 100644 --- a/docs/html/class_d_s_patch_1_1_signal_bus-members.html +++ b/docs/html/class_d_s_patch_1_1_signal_bus-members.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
diff --git a/docs/html/class_d_s_patch_1_1_signal_bus.html b/docs/html/class_d_s_patch_1_1_signal_bus.html index 6286ccd9..c7c16355 100644 --- a/docs/html/class_d_s_patch_1_1_signal_bus.html +++ b/docs/html/class_d_s_patch_1_1_signal_bus.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
diff --git a/docs/html/classes.html b/docs/html/classes.html index 046f781b..554a3eca 100644 --- a/docs/html/classes.html +++ b/docs/html/classes.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
diff --git a/docs/html/dir_96ae4afe4ae1b3c2e5b248f6fc6b60cd.html b/docs/html/dir_96ae4afe4ae1b3c2e5b248f6fc6b60cd.html index 41beef8c..761e2df0 100644 --- a/docs/html/dir_96ae4afe4ae1b3c2e5b248f6fc6b60cd.html +++ b/docs/html/dir_96ae4afe4ae1b3c2e5b248f6fc6b60cd.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
diff --git a/docs/html/dir_d44c64559bbebec7f509842c48db8b23.html b/docs/html/dir_d44c64559bbebec7f509842c48db8b23.html index 78cbb066..f09f7e6f 100644 --- a/docs/html/dir_d44c64559bbebec7f509842c48db8b23.html +++ b/docs/html/dir_d44c64559bbebec7f509842c48db8b23.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
diff --git a/docs/html/files.html b/docs/html/files.html index 3405e662..889840dc 100644 --- a/docs/html/files.html +++ b/docs/html/files.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1
diff --git a/docs/html/index.html b/docs/html/index.html index c0b441ec..ff10dd8d 100644 --- a/docs/html/index.html +++ b/docs/html/index.html @@ -26,7 +26,7 @@ Logo -
DSPatch v.11.4.0 +
DSPatch v.11.4.1