// ____ ______ __ // / __ \ / ____// / // / /_/ // / / / // / ____// /___ / /___ PixInsight Class Library // /_/ \____//_____/ PCL 2.4.23 // ---------------------------------------------------------------------------- // pcl/Thread.h - Released 2022-03-12T18:59:29Z // ---------------------------------------------------------------------------- // This file is part of the PixInsight Class Library (PCL). // PCL is a multiplatform C++ framework for development of PixInsight modules. // // Copyright (c) 2003-2022 Pleiades Astrophoto S.L. All Rights Reserved. // // Redistribution and use in both source and binary forms, with or without // modification, is permitted provided that the following conditions are met: // // 1. All redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // 2. All redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names // of their contributors, may be used to endorse or promote products derived // from this software without specific prior written permission. For written // permission, please contact info@pixinsight.com. // // 4. All products derived from this software, in any form whatsoever, must // reproduce the following acknowledgment in the end-user documentation // and/or other materials provided with the product: // // "This product is based on software from the PixInsight project, developed // by Pleiades Astrophoto and its contributors (https://pixinsight.com/)." // // Alternatively, if that is where third-party acknowledgments normally // appear, this acknowledgment must be reproduced in the product itself. // // THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS // INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE, // DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // ---------------------------------------------------------------------------- #ifndef __PCL_Thread_h #define __PCL_Thread_h /// \file pcl/Thread.h #include #include #include namespace pcl { // ---------------------------------------------------------------------------- /*! * \defgroup thread_support Thread Support Classes and Functions */ // ---------------------------------------------------------------------------- /*! * \namespace pcl::ThreadPriority * \brief Thread scheduling priorities. * * * * * * * * * * * *
ThreadPriority::Inherit Inherit the caller's thread priority. This is the default value.
ThreadPriority::Idle Schedule when no other threads are busy.
ThreadPriority::Lowest Schedule more often than \e idle priority, but less than \e low priority.
ThreadPriority::Low Schedule more often than \e lowest priority, but less than \e normal priority.
ThreadPriority::Normal Standard thread priority.
ThreadPriority::High Schedule more often than \e normal priority, but less than \e highest priority.
ThreadPriority::Highest Schedule more often than \e high priority, but less than \e time-critical priority.
ThreadPriority::TimeCritical Schedule as often as possible, taking precedence over any other threads.
ThreadPriority::DefaultMax Default maximum priority. This is a platform-dependent, maximum thread priority recommended for processing modules.
* * Note that not all platforms and operating systems handle thread scheduling * priorities in the same way. In general, modules should use the default * maximum thread priority by specifying ThreadPriority::DefaultMax instead of * hard-coded priority values. Time-critical priority should be reserved for * performance-critical, very brief and fast tasks exclusively, and should only * be used when it is \e really necessary. This is particularly important on * Windows platforms. * * \ingroup thread_support */ namespace ThreadPriority { enum value_type { Inherit, // Inherit caller's thread priority. Idle, // Schedule when no other threads are busy. Lowest, Low, Normal, // Standard thread priority High, Highest, TimeCritical, // Schedule as often as possible, taking precedence over any other threads. #ifdef __PCL_WINDOWS DefaultMax = Normal // On Windows, anything above Normal is the same as TimeCritical ... #else DefaultMax = Highest #endif }; } // ---------------------------------------------------------------------------- /*! * \class Thread * \brief Client-side interface to a PixInsight thread. * * ### TODO: Write a detailed description for %Thread * * \ingroup thread_support */ class PCL_CLASS Thread : public UIObject { public: /*! * Represents a thread priority. */ typedef ThreadPriority::value_type priority; /*! * Constructs a %Thread object. */ Thread(); /*! * Destroys a %Thread object. */ virtual ~Thread() { } /*! * Ensures that the server-side object managed by this instance is uniquely * referenced. * * Since threads are unique objects by nature, calling this member function * has no effect. */ void EnsureUnique() override { // Threads are unique objects by definition. } /*! * Returns a reference to a null %Thread instance. * * A null %Thread does not correspond to an existing thread in the core * PixInsight application. */ static Thread& Null(); /*! * Starts thread execution with the specified scheduling \a priority and CPU * affinity to the specified \a processor. * * After calling this member function, the PixInsight core application will * create a new execution thread from which the Run() virtual member * function will be invoked for this %Thread instance. * * By default, the calling thread's scheduling priority is inherited by * newly created threads. In general, to maximize performance in a way well * adapted to the running platform, ThreadPriority::DefaultMax should be * specified as the value of the \a priority parameter. * * By default, threads have no specific CPU affinity. By specifying a valid * \a processor index, a thread can be scheduled to run on a specific * logical processor. When the specified \a processor is >= 0, the internal * thread dispatcher will set the corresponding CPU affinity when this * thread is executed, just before calling its Run() virtual member * function. This is usually a more convenient way to control thread * affinity than the SetAffinity() member function, because it allows * setting CPU affinity before a thread starts execution. * * \note Currently, thread affinity can only be set on Linux and Windows * platforms. On FreeBSD and Mac OS X, specifying a processor with this * function has no effect. We hope to overcome this limitation in a future * version of PCL. * * \note Since version 1.8.0 of the PixInsight core application, nested * parallelism is fully supported. This means that multiple threads can be * run by calling Thread::Start() from either the root thread or any running * %Thread object. In versions prior to 1.8.0, a thread could only be run * from the root thread. */ void Start( priority = ThreadPriority::Inherit, int processor = -1 ); /*! * Returns a set of processor indices corresponding to this thread's * \e CPU \e affinity. * * The affinity of a thread defines the set of logical processors on which * the thread is eligible to run. %Thread affinity allows to improve * execution speed by restricting each thread to run on a separate * processor. This prevents the performance cost caused by the cache * invalidation that occurs when a process ceases to execute on one * processor and then restarts execution on a different one (e.g. the * infamous ping-pong effect). * * If this thread is not running, this function returns the affinity of the * calling thread. * * \note Currently, this function only works on Linux. On FreeBSD, Mac OS X * and Windows platforms, this function always returns an empty array. We * hope to overcome this limitation in a future version of PCL. */ Array Affinity() const; /*! * Sets the affinity of this thread to the specified set of \a processors. * * Each element on the specified \a processors array is a zero-based index * corresponding to an existing logical processor. The first processor has * index zero and the last one has index n-1, where n is the total number of * logical processors on the host machine. Logical processors include * physical processors and processor cores, as well as logical processors on * systems with hyper-threading technology. * * Returns true iff the operation was performed correctly. In general, this * function returns false if this thread is not running, or if the specified * set contains nonexistent processor indices. It can also return false if * the calling process does not have the necessary privileges, altough this * should not happen under normal conditions. * * \note The CPU affinity of the calling thread cannot be changed with this * function. If this thread is not running, this function returns false and * does nothing. * * \note Currently, thread affinity can only be set on Linux and Windows * platforms. On FreeBSD and Mac OS X, calling this function has no effect. * We hope to overcome this limitation in a future version of PCL. */ bool SetAffinity( const Array& processors ); /*! * Sets the CPU affinity of this thread to the specified \a processor. * * The specified \a processor is a zero-based index corresponding to an * existing logical processor. The first processor has index zero and the * last one has index n-1, where n is the total number of logical processors * on the host machine. Logical processors include physical processors and * processor cores, as well as logical processors on systems with * hyper-threading technology. * * Returns true iff the operation was performed correctly. In general, this * function returns false if this thread is not running, or if the specified * processor does not exist. It can also return false if the calling process * does not have the necessary privileges, altough this should not happen * under normal conditions. * * \note The CPU affinity of the calling thread cannot be changed with this * function. If this thread is not running, this function returns false and * does nothing. * * \note Currently, thread affinity can only be set on Linux and Windows * platforms. On FreeBSD and Mac OS X, calling this function has no effect. * We hope to overcome this limitation in a future version of PCL. */ bool SetAffinity( int processor ); /*! * Forces immediate termination of thread execution. * * \warning Calling this function is dangerous because it causes the * immediate termination of a running thread without giving it a chance to * perform any cleanup. For example, open files will not be closed, locked * objects will not be unlocked, and shared static variables may be left at * invalid states, with unpredictable results. * * \warning Calling this member function is strongly discouraged - Use it * at your own risk */ void Kill(); // ### Dangerous - Use at your own risk! ### /*! * Returns true iff this thread is running. */ bool IsActive() const; /*! * Returns this thread's priority. */ priority Priority() const; /*! * Sets this thread's priority. */ void SetPriority( priority ); /*! * Resets this thread's priority to the default value, which inherits the * calling thread's priority. */ void ResetPriority() { SetPriority( ThreadPriority::Inherit ); } /*! * Suspends execution of the calling thread until this thread terminates * execution. If this thread is not running, this function returns * immediately. * * \warning If this thread does not return from its Run() member function, * for example because this thread hangs or enters an infinite loop, the * thread that calls this function will remain suspended forever (crashed). */ void Wait(); /*! * Suspends execution of the calling thread until one of the following * conditions is met: * * \li This thread terminates execution, or this thread is not running. * \li The specified time interval \a ms in milliseconds has elapsed. * * This member function returns true if this thread has finished execution * before the specified time \a ms in milliseconds has elapsed. It also * returns true if this thread is not running. * * \note Unlike Wait(), this function cannot crash the calling thread if * this thread is crashed, unless a huge amount of time is specified as the * function argument. */ bool Wait( unsigned ms ); /*! * Suspends execution of this thread during the specified time interval * \a ms in milliseconds. */ void Sleep( unsigned ms ); /* * Returns a reference to the current thread (the thread from which this * member function is invoked), or Thread::Null() if the current thread is * either (a) a thread not being controlled by the PixInsight API, or (b) a * thread that has been created by another module. static Thread& CurrentThread(); */ /*! * This member function returns true if and only if it is called from the * root thread. The root thread is the thread where the graphical * user interface is running on the PixInsight core application. * * \note Since version 1.8.0 of the PixInsight core application, nested * parallelism is fully supported. This means that multiple threads can be * run by calling Thread::Start() from either the root thread or any running * %Thread object. In versions prior to 1.8.0, a thread could only be run * from the root thread. */ static bool IsRootThread(); /*! * Returns the total number of running %Thread objects. * * \note This function knows nothing about threads out of PCL control, so it * will return zero if no %Thread instance is currently active, even if * there are other native threads being executed. */ static int NumberOfRunningThreads(); /*! * %Thread execution routine. * * This member function is invoked by the PixInsight core application upon * execution start, just after calling the Start() member function. During * execution of this routine, it is said that this is a running * thread. * * Derived classes must reimplement this member function to provide specific * thread functionality. * * \note There is no problem at all in calling this member function * directly. This may be useful, for example, if the same code must be * executed in a single thread (without calling Start()) and as * multithreaded code. */ virtual void Run() { // Reimplement this function to provide your thread's functionality. } /*! * Returns the current status of this thread. The thread status is a 32-bit * unsigned integer number that can be set for an active thread by calling * its SetStatus() member function. * * %Thread status is primarily intended as an efficient mechanism to send * custom messages to running threads, for thread synchronization or other * control purposes. * * \note This member function is thread-safe. It can be safely called for a * running thread. * * \note This member function blocks the caller's execution until the thread * status can be retrieved. Hence, the operation performed by this function * is expensive in terms of thread synchronization. For a non-blocking * version of this function see the documentation for TryGetStatus(). */ uint32 Status() const; /*! * Attempts to get the current status of this thread without blocking the * caller's execution. * * Returns true iff the thread status could be retrieved and stored in the * specified \a status variable. * * Returns false if the status couldn't be read. In this case the value of * the \a status variable won't be changed. * * \note This member function is thread-safe. It can be safely called for a * running thread. * * \note This is a non-blocking fast version of the Status() member * function. It should be used when acquiring the thread's status is not * strictly necessary to continue thread execution. */ bool TryGetStatus( uint32& status ) const; /*! * Sets the current status of a running thread. See the documentation of * Thread::Status() for more information. * * \note Calling this function for an inactive thread has no effect. The * thread status can only be set for a running thread. * * \note If the high-order bit of \a status is set, an abort message will be * sent to the running thread. See the Abort() member function for more * information. * * \note This member function is thread-safe. It can be safely called for a * running thread, even from other running threads. */ void SetStatus( uint32 status ); /*! * Sends an abort message to a running thread. * * If the thread calls Module->ProcessEvents() after an abort message has * been sent, or if it uses some of the standard status monitoring classes * (such as StandardStatus for example), a ProcessAborted exception will be * thrown automatically in the thread. The exception will be thrown in the * (reimplemented) Thread::Run() member function, where it should be caught * and used to terminate thread execution by returning from Run(). This * mechanism can be used to synchronize and stop running threads in a * controlled and thread-safe way. * * \note A thread abort message means that the high-order bit of a running * thread's status has been set. This member function simply sets the thread * status to 0x80000000. To effectively abort the thread, it should call * Module->ProcessEvents(), as described above, and should stop its * execution after catching a ProcessAborted exception. * * \note This member function is thread-safe. It can be safely called for a * running thread, even from other running threads. */ void Abort() { SetStatus( 0x80000000 ); } /*! * Returns true iff this thread has been aborted. A thread has been aborted * if it has received an abort message by a previous call to Abort(), or by * setting the high-order bit of its thread status word. * * \note This member function is thread-safe. It can be safely called for a * running thread. * * \note This function calls Status() to read the current thread's status. * Consequently, it blocks the caller's execution and has the same * performance problems. For a non-blocking alternative, see TryIsAborted(). */ bool IsAborted() const { return (Status() & 0x80000000) != 0; } /*! * Returns true iff this thread has been aborted, and the current thread's * status could be retrieved without blocking the caller's execution. * * \note This member function is thread-safe. It can be safely called for a * running thread. * * \note This is a non-blocking fast version of the IsAborted() member * function. It should be used when acquiring the thread's status is not * strictly necessary to continue thread execution. */ bool TryIsAborted() const { uint32 status; return TryGetStatus( status ) && (status & 0x80000000) != 0; } /*! * Returns the console output text currently accumulated in this thread. * * When a %Thread object is running (that is, when its IsActive() member * function returns true), no operation on the graphical user interface is * permitted from the thread. This includes console text output. * * When a running thread writes text to the console, for example by calling * Console::Write() or Console::WriteLn(), the text is not sent to the * console (which in fact would raise an Error exception), but it is instead * appended to the thread's console output text. The accumulated * output text can be sent to the console once the thread has finished * execution, or it can be retrieved by calling this member function. */ String ConsoleOutputText() const; /*! * Returns true iff this thread has any accumulated console output text that * still has not been flushed or cleared. * * For information on thread console output, refer to the documentation for * the ConsoleOutputText() member function. */ bool HasConsoleOutputText() const { return !ConsoleOutputText().IsEmpty(); } /*! * Erases the accumulated console output text in this thread. * * For information on thread console output, refer to the documentation for * the ConsoleOutputText() member function. */ void ClearConsoleOutputText(); /*! * Sends any accumulated console output text in this thread to the console. * * After writing the accumulated text to the console, this member function * clears it, so that repeated calls to this function will have no effect. * * For information on thread console output, refer to the documentation for * the ConsoleOutputText() member function. * * \note This member function must only be called from the root thread. * Calling it from a running %Thread object has no effect. */ void FlushConsoleOutputText(); /*! * Returns the maximum number of threads that can be used concurrently to * process a set of items. * * \param count Number of processing units. A processing unit can * be a single pixel, a row of pixels, or any suitable item, * according to the task being performed by the caller. * * \param overheadLimit %Thread overhead limit in processing units. The * function returns a maximum number of threads such that no * thread would have to process less processing units than this * value. The default overhead limit is one processing unit. * * This function takes into account the number of existing processors in * the system, as well as the maximum number of processors currently allowed * for external processes by the core application, and the number of threads * currently active. The following global variables are taken into account * (see the PixInsightSettings class for more information about global * variables on the PixInsight platform): * * * * * * * * * * *
Process/EnableParallelProcessingIf this global flag is false, it means that parallel processing * has been globally disabled for the entire platform, so this function * will always return one, irrespective of the number of existing * processors.
Process/EnableParallelModuleProcessingIf this global flag is false, it means that parallel processing * has been disabled for all installed modules, so this function will * always return one, as in the previous case.
Process/MaxProcessorsThis global integer variable is the maximum number of processors * allowed for installed modules, which is always less than or equal to * the number of existing processors in the system. This function will * never return a number of threads greater than the value of this * variable.
* * The number of processors term refers to the number of existing * logical processors in the system. These include all physical * processors in multiprocessor systems, as well as all existing processor * cores in multicore processors, and virtual processors in systems with * HyperThreading or equivalent technology. * * Since version 1.8.0 of the PixInsight core application, nested * parallelism is fully supported. This means that multiple threads can be * executed concurrently from a running thread. This function will take into * account the number of already running threads, as provided by the * Thread::NumberOfRunningThreads() static member function, to help prevent * exceeding the maximum number of threads allowed by the platform (see the * global variables in the table above). In any event, the calling module is * entirely responsible to comply with these restrictions. * * \note A module must never try to run more threads concurrently than the * amount returned by this function. Failure to follow this rule will * invalidate a module for certification. */ static int NumberOfThreads( size_type count, size_type overheadLimit = 1u ); /*! * Returns a list of per-thread counts optimized for parallel processing of * a set of items. * * \param count Number of processing units. A processing unit can * be a single pixel, a row of pixels, or any suitable item, * according to the task being performed by the caller. * * \param overheadLimit %Thread overhead limit in processing units. The * function returns a list with a maximum length such that no * thread would have to process less processing units than this * value. The default overhead limit is one processing unit. * * \param maxThreads Maximum number of threads to use. The length of the * returned list will be at most either this value, or the * maximum number of threads currently allowed for the calling * process, whichever is less. The default value of this * parameter does not impose a practical limit. * * This function takes into account the number of existing logical * processors in the system, as well as the maximum number of processors * currently allowed for external processes by the PixInsight core * application, and the number of threads currently active. See the * NumberOfThreads() static member function for more information on thread * execution and the global settings governing their use in PixInsight. * * This function returns a dynamic array of unsigned integers, where each * element is the number of items that the corresponding thread should * process in order to make an optimal usage of the processor resources * currently available. The length of the returned array is the maximum * number of threads that the calling process should execute concurrently to * process the specified number of items, with the specified overhead limit * and maximum number of processors. * * In the current implementation of this function, the returned array tends * to spread the total work load uniformly across the threads available. * Future implementations may consider additional factors, including the * possibility of using new global settings specific for thread execution * optimization. For this reason, under normal conditions a module should * always use the result of calling this function to define a thread * execution schedule. See also OptimalThreadLoadsAligned() for a variant of * this function with prescribed item alignment. * * \note A module must never try to run more threads concurrently than the * length of the array returned by this function. Failure to follow this * rule will invalidate a module for certification. * * \sa OptimalThreadLoadsAligned() */ static Array OptimalThreadLoads( size_type count, size_type overheadLimit = 1u, int maxThreads = PCL_MAX_PROCESSORS ); /*! * Returns a list of per-thread counts optimized for parallel processing of * a contiguous set of items stored with a prescribed alignment. * * \param count Number of processing units. A processing unit can * be a single pixel, a row of pixels, or any suitable item, * according to the task being performed by the caller. For * optimal performance, the size in bytes of a processing unit * should be even, assuming that the task will be applied to a * contiguous list of \a count items. * * \param align Item alignment. The function will return a list of counts, * where all counts but the last one are guaranteed to be * integer multiples of this parameter. The default value is 16. * * \param overheadLimit %Thread overhead limit in processing units. The * function returns a list with a maximum length such that no * thread would have to process less processing units than this * value. The default overhead limit is one processing unit. * * \param maxThreads Maximum number of threads to use. The length of the * returned list will be at most either this value, or the * maximum number of threads currently allowed for the calling * process (whichever is less), or maybe a smaller length, if * necessary to enforce the specified alignment. The default * value of this parameter does not impose a practical limit. * * Other than the prescribed alignment, this function is equivalent to its * unaligned counterpart OptimalThreadLoads(). * * \sa OptimalThreadLoads() */ static Array OptimalThreadLoadsAligned( size_type count, int align = 16, size_type overheadLimit = 1u, int maxThreads = PCL_MAX_PROCESSORS ); private: int m_processorIndex = -1; Thread( void* h ) : UIObject( h ) { } void* CloneHandle() const override; protected: virtual bool IsStealth() const { return false; } friend class ThreadDispatcher; }; // ---------------------------------------------------------------------------- /*! * Suspends the calling thread from execution until the specified time \a ms in * milliseconds has elapsed, or until a signal is delivered to the calling * thread that terminates the process or causes activation of a signal-catching * routine. * \ingroup thread_support */ void PCL_FUNC Sleep( unsigned ms ); // ---------------------------------------------------------------------------- } // pcl #endif // __PCL_Thread_h // ---------------------------------------------------------------------------- // EOF pcl/Thread.h - Released 2022-03-12T18:59:29Z