thread.h
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:19k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * thread.h
  3.  *
  4.  * Executable thread encapsulation class (pre-emptive if OS allows).
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: thread.h,v $
  30.  * Revision 1.23  2000/06/26 11:17:19  robertj
  31.  * Nucleus++ port (incomplete).
  32.  *
  33.  * Revision 1.22  2000/02/29 12:26:14  robertj
  34.  * Added named threads to tracing, thanks to Dave Harvey
  35.  *
  36.  * Revision 1.21  1999/06/06 05:07:17  robertj
  37.  * Fixed documentation error.
  38.  *
  39.  * Revision 1.20  1999/03/09 02:59:51  robertj
  40.  * Changed comments to doc++ compatible documentation.
  41.  *
  42.  * Revision 1.19  1999/02/16 08:11:17  robertj
  43.  * MSVC 6.0 compatibility changes.
  44.  *
  45.  * Revision 1.18  1998/11/20 03:18:33  robertj
  46.  * Added thread WaitForTermination() function.
  47.  *
  48.  * Revision 1.17  1998/10/31 12:47:59  robertj
  49.  * Removed ability to start threads immediately, race condition with vtable (Main() function).
  50.  *
  51.  * Revision 1.16  1998/09/23 06:21:41  robertj
  52.  * Added open source copyright license.
  53.  *
  54.  * Revision 1.15  1996/03/02 03:15:51  robertj
  55.  * Added automatic deletion of thread object instances on thread completion.
  56.  *
  57.  * Revision 1.14  1995/12/10 11:44:32  robertj
  58.  * Fixed bug in non-platform threads and semaphore timeouts.
  59.  *
  60.  * Revision 1.13  1995/11/21 11:49:44  robertj
  61.  * Added timeout on semaphore wait.
  62.  *
  63.  * Revision 1.12  1995/07/31 12:10:40  robertj
  64.  * Added semaphore class.
  65.  *
  66.  * Revision 1.11  1995/06/17 11:13:35  robertj
  67.  * Documentation update.
  68.  *
  69.  * Revision 1.10  1995/03/14 12:42:49  robertj
  70.  * Updated documentation to use HTML codes.
  71.  *
  72.  * Revision 1.9  1995/01/16  09:42:13  robertj
  73.  * Documentation.
  74.  *
  75.  * Revision 1.8  1994/09/25  10:45:22  robertj
  76.  * Virtualised IsNoLongerBlocked for unix platform.
  77.  *
  78.  * Revision 1.6  1994/08/22  00:46:48  robertj
  79.  * Added pragma fro GNU C++ compiler.
  80.  *
  81.  * Revision 1.5  1994/08/21  23:43:02  robertj
  82.  * Added SuspendBlock state to cooperative multi-threading to fix logic fault.
  83.  *
  84.  * Revision 1.4  1994/08/04  12:32:22  robertj
  85.  * Better name of thread block check function.
  86.  *
  87.  * Revision 1.3  1994/07/21  12:33:49  robertj
  88.  * Moved cooperative threads to common.
  89.  *
  90.  * Revision 1.2  1994/07/02  03:03:49  robertj
  91.  * Added restartable threads.
  92.  *
  93.  * Revision 1.1  1994/06/25  11:55:15  robertj
  94.  * Initial revision
  95.  *
  96.  */
  97. #define _PTHREAD
  98. #ifdef __GNUC__
  99. #pragma interface
  100. #endif
  101. #ifdef Priority
  102. #undef Priority
  103. #endif
  104. class PSemaphore;
  105. ///////////////////////////////////////////////////////////////////////////////
  106. // PThread
  107. /** This class defines a thread of execution in the system. A {it thread} is
  108.    an independent flow of processor instructions. This differs from a
  109.    {it process} which also embodies a program address space and resource
  110.    allocation. So threads can share memory and resources as they run in the
  111.    context of a given process. A process always contains at least one thread.
  112.    This is reflected in this library by the #PProcess# class being
  113.    descended from the PThread class.
  114.    The implementation of a thread is platform dependent. Not all platforms
  115.    support concurrent threads within a process or even concurrent processes!
  116.    For example, MS-DOS has no form of multi-threading or multi-processing,
  117.    Microsoft Windows has a cooperative multi-processing but no multi-threading.
  118.    Unix has full pre-emptive multi-processing but most cannot do multiple
  119.    threads within that process while some Unix systems and Windows NT have
  120.    full preemptive proceses and threads.
  121.    If a platform does not directly support multiple threads, the library will
  122.    them using a cooperative co-routine technique. This requires that each
  123.    thread of execution within a process, voluntarily yields control to other
  124.    threads. This will occur if the thread is blocked inside an I/O function
  125.    on a #PChannel# or when the #PThread::Yield()# function is
  126.    explicitly called.
  127.    
  128.    Note that this is {bf cooperative}. An endless loop will stop all
  129.    threads in a process, possibly all processes on some platforms. If a
  130.    lengthy operation is to take place that does not involve blocking I/O,
  131.    eg pure computation or disk file I/O, then it is the responsiblity of the
  132.    programmer to assure enough yielding for background threads to execute.
  133.  */
  134. class PThread : public PObject
  135. {
  136.   PCLASSINFO(PThread, PObject);
  137.   public:
  138.   /**@name Construction */
  139.   //@{
  140.     /// Codes for thread priorities.
  141.     enum Priority {
  142.       /// Will only run if all other threads are blocked.
  143.       LowestPriority,   
  144.       /// Runs approximately half as often as normal.
  145.       LowPriority,      
  146.       /// Normal priority for a thread.
  147.       NormalPriority,   
  148.       /// Runs approximately twice as often as normal.
  149.       HighPriority,     
  150.       /// Is only thread that will run, unless blocked.
  151.       HighestPriority,  
  152.       NumPriorities
  153.     };
  154.     /// Codes for thread autodelete flag
  155.     enum AutoDeleteFlag {
  156.       /// Automatically delete thread object on termination.
  157.       AutoDeleteThread,   
  158.       /// Don't delete thread as it may not be on heap.
  159.       NoAutoDeleteThread  
  160.     };
  161.     /** Create a new thread instance. Unless the #startSuspended#
  162.        parameter is TRUE, the threads #Main()# function is called to
  163.        execute the code for the thread.
  164.        
  165.        Note that the exact timing of the execution of code in threads can
  166.        never be predicted. Thus you you can get a race condition on
  167.        intialising a descendent class. To avoid this problem a thread is
  168.        always started suspended. You must call the Resume() function after
  169.        your descendent class construction is complete.
  170.        If synchronisation is required between threads then the use of
  171.        semaphores is essential.
  172.        If the #deletion# is set to #AutoDeleteThread#
  173.        then the PThread is assumed to be allocated with the new operator and
  174.        may be freed using the delete operator as soon as the thread is
  175.        terminated or executes to completion (usually the latter).
  176.        The stack size specified is {bf not} simply in bytes. It is a value
  177.        that is multiplied by a factor into bytes depending on the target
  178.        platform. For example a Unix system with a RISC processor may use
  179.        significantly more stack than an MS-DOS platform. These sizes are
  180.        normalised to the "stack factor" provided here. For some platforms, eg
  181.        Windows NT, the stack size is only an initial size and the stack will
  182.        automatically be increased as required.
  183.      */
  184.     PThread(
  185.       PINDEX stackSize,                 /// Size of stack to use for thread.
  186.       AutoDeleteFlag deletion = AutoDeleteThread,
  187.         /// Automatically delete PThread instance on termination of thread.
  188.       Priority priorityLevel = NormalPriority,  /// Initial priority of thread.
  189.       const PString & ThreadName = "" /// The name of the thread (for Debug/Trace)
  190.     );
  191.     /** Destroy the thread, this simply calls the #Terminate()# function
  192.        with all its restrictions and penalties. See that function for more
  193.        information.
  194.        Note that the correct way for a thread to terminate is to return from
  195.        the #Main()# function.
  196.      */
  197.     ~PThread();
  198.   //@}
  199.   /**@name Overrides from PObject */
  200.   //@{
  201.     /**Standard stream print function.
  202.        The PObject class has a << operator defined that calls this function
  203.        polymorphically.
  204.       */
  205.     void PrintOn(
  206.       ostream & strm    /// Stream to output text representation
  207.     ) const;
  208.   //@}
  209.   /**@name Control functions */
  210.   //@{
  211.     /** Restart a terminated thread using the same stack priority etc that
  212.        was current when the thread terminated.
  213.        
  214.        If the thread is still running then this function is ignored.
  215.      */
  216.     virtual void Restart();
  217.     /** Terminate the thread. It is highly recommended that this is not used
  218.        except in abnormal abort situations as not all clean up of resources
  219.        allocated to the thread will be executed. This is especially true in
  220.        C++ as the destructors of objects that are automatic variables are not
  221.        called causing at the very least the possiblity of memory leaks.
  222.        Note that the correct way for a thread to terminate is to return from
  223.        the #Main()# function or self terminate by calling
  224.        #Terminate()# within the context of the thread which can then
  225.        assure that all resources are cleaned up.
  226.      */
  227.     virtual void Terminate();
  228.     /** Determine if the thread has been terminated or ran to completion.
  229.        @return
  230.        TRUE if the thread has been terminated.
  231.      */
  232.     virtual BOOL IsTerminated() const;
  233.     /** Block and wait for the thread to terminate.
  234.        @return
  235.        FALSE if the thread has not terminated and the timeout has expired.
  236.      */
  237.     void WaitForTermination() const;
  238.     BOOL WaitForTermination(
  239.       const PTimeInterval & maxWait  /// Maximum time to wait for termination.
  240.     ) const;
  241.     /** Suspend or resume the thread.
  242.     
  243.        If #susp# is TRUE this increments an internal count of
  244.        suspensions that must be matched by an equal number of calls to
  245.        #Resume()# or #Suspend(FALSE)# before the
  246.        thread actually executes again.
  247.        If #susp# is FALSE then this decrements the internal count of
  248.        suspensions. If the count is <= 0 then the thread will run. Note that
  249.        the thread will not be suspended until an equal number of
  250.        #Suspend(TRUE)# calls are made.
  251.      */
  252.     virtual void Suspend(
  253.       BOOL susp = TRUE    /// Flag to suspend or resume a thread.
  254.     );
  255.     /** Resume thread execution, this is identical to
  256.        #Suspend(FALSE)#.
  257.      */
  258.     virtual void Resume();
  259.     /** Determine if the thread is currently suspended. This checks the
  260.        suspension count and if greater than zero returns TRUE for a suspended
  261.        thread.
  262.        @return
  263.        TRUE if thread is suspended.
  264.      */
  265.     virtual BOOL IsSuspended() const;
  266.     /// Suspend the current thread for the specified amount of time.
  267.     virtual void Sleep(
  268.       const PTimeInterval & delay   /// Time interval to sleep for.
  269.     );
  270.     /** Set the priority of the thread relative to other threads in the current
  271.        process.
  272.      */
  273.     virtual void SetPriority(
  274.       Priority priorityLevel    /// New priority for thread.
  275.     );
  276.     /** Get the current priority of the thread in the current process.
  277.        @return
  278.        current thread priority.
  279.      */
  280.     virtual Priority GetPriority() const;
  281.     /** Get the name of the thread. Thread names are a optional debugging aid.
  282.        @return
  283.        current thread name.
  284.      */
  285.     virtual PString GetThreadName() const;
  286.     /** Change the name of the thread. Thread names are a optional debugging aid.
  287.        @return
  288.        current thread name.
  289.      */
  290.     virtual void SetThreadName(
  291.       const PString & name        /// New name for the thread.
  292.     );
  293.   //@}
  294.   /**@name Miscellaneous */
  295.   //@{
  296.     /** User override function for the main execution routine of the thread. A
  297.        descendent class must provide the code that will be executed in the
  298.        thread within this function.
  299.        
  300.        Note that the correct way for a thread to terminate is to return from
  301.        this function.
  302.      */
  303.     virtual void Main() = 0;
  304.     /** Get the currently running thread object instance. It is possible, even
  305.        likely, that the smae code may be executed in the context of differenct
  306.        threads. Under some circumstances it may be necessary to know what the
  307.        current codes thread is and this static function provides that
  308.        information.
  309.        @return
  310.        pointer to current thread.
  311.      */
  312.     static PThread * Current();
  313.     /** Yield to another thread. If there are no other threads then this
  314.        function does nothing. Note that on most platforms the threading is
  315.        cooperative and this function must be called for other threads to run
  316.        at all. There may be an implicit call to Yield within the I/O functions
  317.        of #PChannel# classes. This is so when a thread is I/O blocked then
  318.        other threads can, as far as possible, continue to run.
  319.        
  320.        If the platform directly supports multiple threads then this function
  321.        will do nothing.
  322.      */
  323.     static void Yield();
  324.   //@}
  325.   protected:
  326.     void InitialiseProcessThread();
  327.     /* Initialialise the primordial thread, the one in the PProcess. This is
  328.        required due to the bootstrap logic of processes and threads.
  329.      */
  330. #ifndef P_PLATFORM_HAS_THREADS
  331.     virtual BOOL IsNoLongerBlocked();
  332.     /* Check if the condition that has blocked a thread in an I/O function,
  333.        for example, has ceased. This is required by the internal cooperative
  334.        thread scheduler.
  335.        This function is not present for platforms that support threads.
  336.        
  337.        <H2>Returns:</H2>
  338.        TRUE if the thread is no longer blocked.
  339.      */
  340. #endif
  341.   private:
  342.     PThread();
  343.     // Create a new thread instance as part of a PProcess class.
  344.     friend class PProcess;
  345.     // So a PProcess can get at PThread() constructor but nothing else.
  346.     PThread(const PThread &) { }
  347.     // Empty constructor to prevent copying of thread instances.
  348.     PThread & operator=(const PThread &) { return *this; }
  349.     // Empty assignment operator to prevent copying of thread instances.
  350.     BOOL autoDelete;
  351.     // Automatically delete the thread on completion.
  352.     // Give the thread a name for debugging purposes.
  353.     PString threadName;
  354. #ifndef P_PLATFORM_HAS_THREADS
  355.     void AllocateStack(
  356.       PINDEX stackSize  // Size of the stack to allocate.
  357.     );
  358.     /* Allocate the stack for the thread.
  359.        The stack size specified is {bf not} simply in bytes. It is a value
  360.        that is multiplied by a factor into bytes depending on the target
  361.        platform. For example a Unix system with a RISC processor may use
  362.        significantly more stack than an MS-DOS platform. These sizes are
  363.        normalised to the "stack factor" provided here. For some platforms, eg
  364.        Windows NT, the stack size is only an initial size and the stack will
  365.        automatically be increased as required.
  366.        This function is not present for platforms that support threads.
  367.      */
  368.     void ClearBlock();
  369.     /* Clear the blocked thread. This is used by platform dependent code to
  370.        signal to the common code scheduler that the thread is no longer
  371.        blocked.
  372.        This function is not present for platforms that support threads.
  373.      */
  374.     void BeginThread();
  375.     /* Function to start #Main()# and exit when completed.
  376.        This function is not present for platforms that support threads.
  377.      */
  378.     virtual void SwitchContext(
  379.       PThread * from    // Thread being switched from.
  380.     );
  381.     /* Do the machinations needed to jump to the current thread. This is a
  382.        platform dependent function that utilises the standard C
  383.        #setjmp()# and #longjmp()# functions to implement
  384.        the co-routines.
  385.     
  386.        This function is not present for platforms that support threads.
  387.      */
  388.     // Member fields
  389.     Priority basePriority;
  390.     /* The threads priority level, relative to other threads.
  391.        This variable is not present for platforms that support threads.
  392.      */
  393.     int dynamicPriority;
  394.     /* The threads priority during this scheduled slice. A thread that has not
  395.        been scheduled has its dynamic priority increased so that next time
  396.        the scheduler is looking for a thread to run it has a better chance of
  397.        executing. Once a thread is executed the dynamic priority is set back
  398.        to the base priority as set by #SetPriority()#.
  399.        This variable is not present for platforms that support threads.
  400.      */
  401.     int suspendCount;
  402.     /* The threads count of calls to #Suspend()# or #Resume()#.
  403.        If <=0 then can run, if >0 means suspended and is not to be scheduled.
  404.        This variable is not present for platforms that support threads.
  405.      */
  406.     PTimer sleepTimer;
  407.     /* Time for thread to remain asleep. Thread is not scheduled while this
  408.        is running after a #Sleep()# call.
  409.        This variable is not present for platforms that support threads.
  410.      */
  411.     PSemaphore * blockingSemaphore;
  412.     /* Semaphore that is blocking this thread.
  413.        This variable is not present for platforms that support threads.
  414.      */
  415.     PThread * link;
  416.     /* Link to next thread in circular list. The use of a list rather than
  417.        priority queues or other sophisticated task queuing technique is to
  418.        simplify the scheduler. It is expected that any given process will not
  419.        have a large number of threads, ie less than approximately ten, so the
  420.        overhead of the list search is small in comparison to the overhead in
  421.        complex data structures.
  422.        This variable is not present for platforms that support threads.
  423.      */
  424.     enum {
  425.       Starting,         // Thread is starting up.
  426.       Running,          // Thread is the currently executing context.
  427.       Waiting,          // Thread is waiting to be scheduled.
  428.       Sleeping,         // Thread is sleeping until sleepTimer is up.
  429.       Suspended,        // Thread is currently suspended.
  430.       BlockedIO,        // Thread is currently blocked in I/O.
  431.       SuspendedBlockIO, // Thread is blocked {bf and} suspended.
  432.       BlockedSem,       // Thread is currently blocked by a semaphore.
  433.       SuspendedBlockSem,// Thread is blocked {bf and} suspended.
  434.       Terminating,      // Thread is terminating but has not died yet.
  435.       Terminated        // Thread has terminated.
  436.     } status;
  437.     /* Thread status for scheduler handling.
  438.        This variable is not present for platforms that support threads.
  439.      */
  440.     jmp_buf context;
  441.     /* Buffer for context switching.
  442.        This variable is not present for platforms that support threads.
  443.      */
  444.     char PSTATIC * stackBase;
  445.     /* Base of stack allocated for the thread. The PSTATIC is for DOS-Windows.
  446.        This variable is not present for platforms that support threads.
  447.      */
  448.     char PSTATIC * stackTop;
  449.     /* Top of stack allocated for the thread.
  450.        This variable is not present for platforms that support threads.
  451.      */
  452.     friend class PSemaphore;
  453. #endif
  454. #ifdef DOC_PLUS_PLUS
  455. };
  456. #endif
  457. // Class declaration continued in platform specific header file ///////////////