home *** CD-ROM | disk | FTP | other *** search
/ Stone Design / Stone Design.iso / Stone_Friends / NeXT-Icons / next-icon@gun.com / Apps / ImagePortfolio / threads.subproj / objectThreadPerform.h < prev    next >
Encoding:
Text File  |  1993-06-03  |  8.3 KB  |  139 lines

  1. // -------------------------------------------------------------------------------------
  2. // objectThreadPerform.hm
  3. // author: Martin D. Flynn
  4. //
  5. // This category of Object provides a general solution for thread support which includes
  6. // a solution for allowing threads to communicate with the window/event manager.
  7. //
  8. // Using 'forkPerform:detach:', a thread can be created to perform some action in the
  9. // background while the window manager (main thread) is free to handle events.
  10. //
  11. // In addition to creating new threads, support is provided to allow a forked thread to
  12. // communicate with the main thread to tell it to execute actions, such as drawing in a
  13. // view, and even returning values.  This is accomplished through calls to
  14. // 'mainThreadPerform:with:wait:'.  This method can be called from any thread, making sure
  15. // that the main thread is the only thread that will process the specified action.  These
  16. // methods are object independent, meaning that 'mainThreadPerform:wait:' can be sent to
  17. // ANY object from ANY thread.  For instance, a forked thread could set the title of some
  18. // button with the following:
  19. //   [someButtonId mainThreadPerform:@selector(setTitleNoCopy:) with:aStaticTitle wait:NO];
  20. // (A forked thread should not try to set the title of a button itself, or execute any
  21. // other method that causes drawing to occur.  This is because it has no way of knowing
  22. // what drawing may already be occurring, and it may in fact cause drawing to occur in a
  23. // view other than where it was originally intended.)
  24. //
  25. // The return value can also be obtained from the method executed from the main thread by
  26. // setting 'wait:YES'.  For example, to wait for a return value from a method executed
  27. // from the main thread you could issue the following message:
  28. //   rtn = [myObject mainThreadPerform:@selector(showErrorPanel:) with:errorMsg wait:YES];
  29. // The value that 'showErrorPanel:' returned in the main thread would be returned to the
  30. // calling thread.  This is helpful when a thread wishes to display an error panel, then
  31. // act on the response from the user.
  32. //
  33. // -------------------------------------------------------------------------------------
  34. #import <mach/cthreads.h>
  35. #import <objc/Object.h>
  36.  
  37. // -------------------------------------------------------------------------------------
  38. // thread perform macros (Object category enhancements)
  39. // (see 'mainThreadPerform:wait:' below for more informaiton)
  40. #define    isMainTHREAD            [Object isMainThread]
  41. #define    _cmdPERFORM(P)            [self mainThreadPerform:_cmd with:(id)(P) wait:NO]
  42. #define    _cmdPERFORM2(P1,P2)        [self mainThreadPerform:_cmd with:(id)P1 with:(id)P2 wait:NO]
  43. #define _cmdPERFORMw(P)            [self mainThreadPerform:_cmd with:(id)(P) wait:YES]
  44. #define    _cmdINVOKE(P)            { if (!isMainTHREAD) return _cmdPERFORM(P); }
  45. #define    _cmdINVOKE2(P1,P2)        { if (!isMainTHREAD) return _cmdPERFORM2(P1,P2); }
  46. #define    _cmdINVOKEw(P)            { if (!isMainTHREAD) return _cmdPERFORMw(P); }
  47.  
  48. // -------------------------------------------------------------------------------------
  49. @interface Object(ThreadPerform)
  50. // -------------------------------------------------------------------------------------
  51. + initThreadSupport;
  52. //  This initialization will occur automatically when 'forkPerform:...' is executed from
  53. //  the main thread.  You may call this method to explicitly initialize this thread
  54. //  support prior to calling 'forkPerform:...'
  55. //
  56. // -------------------------------------------------------------------------------------
  57. + (BOOL)isMainThread;
  58. - (BOOL)isMainThread;
  59. //  These methods return true if called from the main thread, else they return false.
  60. //  Valid only after a call to 'initThreadSupport', or 'forkPerform:...', has been made.
  61. //
  62. // -------------------------------------------------------------------------------------
  63. - (cthread_t)cthreadSelf;
  64. //  cthreadSelf returns the equivalent of cthread_self().  This method allows easier
  65. //  access to the thread handle when running the application under 'gdb'.
  66. //
  67. // -------------------------------------------------------------------------------------
  68. - perform:(SEL)selector with:arg1 with:arg2 argCount:(int)argCount;
  69. //  This method is a shell for the individual 'perform:[with:[with:]]' with the specified
  70. //  number of arguments.
  71. //  An argCount of 0 would send [self perform:selector];
  72. //  An argCount of 1 would send [self perform:selector with:arg1]; 
  73. //  An argCount of 2 would send [self perform:selector with:arg1 with:arg2];
  74. //  Any other value for argCount will be ignored.
  75. //
  76. // -------------------------------------------------------------------------------------
  77. - mainThreadPerform:(SEL)aSelector wait:(BOOL)waitFlag;
  78. - mainThreadPerform:(SEL)aSelector with:anArg wait:(BOOL)waitFlag;
  79. - mainThreadPerform:(SEL)aSelector with:anArg0 with:anArg1 wait:(BOOL)waitFlag;
  80. //  This method will cause aSelector to be executed by the main thread.     If the calling
  81. //  thread is not the main thread, this method sends an aSelector message through a Mach
  82. //  port to the main thread to be executed.  If the calling thread is the main thread,
  83. //  then the aSelector message is sent directly.  If waitFlag is true, then the calling
  84. //  thread will be suspended until the main thread completes the execution of the message,
  85. //  and the return value will be that of the aSelector message executed from the main
  86. //  thread.  If waitFlag is false, then this method returns (id)nil.
  87. //    Macros:    _cmdPERFORM(anArg)        /* [self mainThreadPerform:_cmd with:anArg wait:NO]   */
  88. //             _cmdPERFORMw(anArg)        /* [self mainThreadPerform:_cmd with:anArg wait:YES]  */
  89. //             _cmdINVOKE(anArg)        /* { if (!isMainTHREAD) return _cmdPERFORM(anArg); }  */
  90. //             _cmdINVOKEw(anArg)        /* { if (!isMainTHREAD) return _cmdPERFORMw(anArg); } */
  91. //
  92. //  Note on use of _cmdINVOKE(anArg) and _cmdINVOKEw(anArg) :
  93. //    To guarentee that a method is executed from the main thread the method need only 
  94. //    include '_cmdINVOKE(anArg);' at the beginning of the method.  When this macro is
  95. //    executed, it checks to see if it is the main thread.  If it is not then it is sent
  96. //    to the main thread and the macro causes the method to return.  If it is executed
  97. //    from the main thread, as it would be after being sent to _cmdPERFORM(anArg), then
  98. //    the method is allowed to execute normally.  Using _cmdINVOKEw(anArg) performs
  99. //    the same as _cmdINVOKE(anArg) except that it waits for the main thread to finish
  100. //    execution of the method before returning.  It is important to note that if this
  101. //    method is implemented in a subclass, it is important that the subclass implementation
  102. //    duplicate the the call to the macro at the beginning of the method.  Otherwise
  103. //    unpredictable results may occur.
  104. //
  105. //  Example use of _cmdINVOKE(anArg);
  106. //        - setButtonState:(BOOL)newState
  107. //        {
  108. //            _cmdINVOKE(newState);
  109. //            [myButton setState:newState];
  110. //            // ... other code here ...
  111. //            return self;
  112. //        }
  113. // 
  114. // -------------------------------------------------------------------------------------
  115. - (cthread_t)forkPerform:(SEL)aSelector detach:(BOOL)detach;
  116. - (cthread_t)forkPerform:(SEL)aSelector with:anArg detach:(BOOL)detach;
  117. - (cthread_t)forkPerform:(SEL)aSelector with:anArg0 with:anArg1 detach:(BOOL)detach;
  118. //    This method creates a new thread in which the aSelector message is executed.  The
  119. //    cthread handle for the created thread is returned if 'detach:NO' was specified, and
  120. //  normal cthread functions may be performed on this handle.  Nil is returned if
  121. //  'detach:YES' was specified, since there is no guarantee that the returned value would
  122. //  ever be valid (ie. The thread could terminate before you use the handle).
  123. //     
  124. // -------------------------------------------------------------------------------------
  125. - (BOOL)threadIsActive:(cthread_t)theCthread;
  126. //  threadIsActive: returns YES if theCthread is still active, otherwise NO.
  127. //  This function queries the cthread_t structure which contains information concerning
  128. //  the state of the thread, including whether theCthread has completed, or not.  If
  129. //  theCthread is nil, then threadIsActive will return NO.
  130. //     
  131. // -------------------------------------------------------------------------------------
  132. - terminateThread;
  133. //    This method will terminate the calling thread.  This method does not return.  If 
  134. //  this method is subclassed, then the subclass should make sure to call 
  135. //  [super terminateThread] to terminate the thread.
  136. //     
  137. // -------------------------------------------------------------------------------------
  138. @end
  139.