home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1995 August / NEBULA.bin / SourceCode / Classes / SampleClasses / objectThreadPerform.h < prev    next >
Encoding:
Text File  |  1992-08-04  |  7.7 KB  |  125 lines

  1. // -------------------------------------------------------------------------------------
  2. // objectThreadPerform.m
  3. // Martin D. Flynn, NeXT Computer, Inc.
  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. // Permission is granted to freely redistribute this source code, and to use fragments
  35. // of this code in your own applications if you find them to be useful.  This class,
  36. // along with the source code, come with no warranty of any kind, and the user assumes
  37. // all responsibility for its use.
  38. // -------------------------------------------------------------------------------------
  39. #import <mach/cthreads.h>
  40. #import <objc/Object.h>
  41.  
  42. // -------------------------------------------------------------------------------------
  43. // thread perform macros (Object category enhancements)
  44. // (see 'mainThreadPerform:wait:' below for more informaiton)
  45. #define isMainTHREAD            [Object isMainThread]
  46. #define _cmdPERFORM(P)          [self mainThreadPerform:_cmd with:(id)(P) wait:NO]
  47. #define _cmdPERFORMw(P)         [self mainThreadPerform:_cmd with:(id)(P) wait:YES]
  48. #define _cmdINVOKE(P)           { if (!isMainTHREAD) return _cmdPERFORM(P); }
  49. #define _cmdINVOKEw(P)          { if (!isMainTHREAD) return _cmdPERFORMw(P); }
  50.  
  51. // -------------------------------------------------------------------------------------
  52. @interface Object(ThreadPerform)
  53. // -------------------------------------------------------------------------------------
  54. void objectThreadPerformInit();
  55. + initThreadSupport;
  56. //  This initialization will occur automatically when 'forkPerform:...' is executed from
  57. //  the main thread.  You may call this method to explicitly initialize this thread
  58. //  support prior to calling 'forkPerform:...'
  59. //
  60. // -------------------------------------------------------------------------------------
  61. + (BOOL)isMainThread;
  62. - (BOOL)isMainThread;
  63. //  These methods return true if called from the main thread, else they return false.
  64. //  Valid only after a call to 'initThreadSupport', or 'forkPerform:...', has been made.
  65. //
  66. // -------------------------------------------------------------------------------------
  67. - perform:(SEL)selector with:arg1 with:arg2 argCount:(int)argCount;
  68. //  This method is a shell for the individual 'perform:[with:[with:]]' with the specified
  69. //  number of arguments.
  70. //  An argCount of 0 would send [self perform:selector];
  71. //  An argCount of 1 would send [self perform:selector with:arg1]; 
  72. //  An argCount of 2 would send [self perform:selector with:arg1 with:arg2];
  73. //  Any other value for argCount will be ignored.
  74. //
  75. // -------------------------------------------------------------------------------------
  76. - mainThreadPerform:(SEL)aSelector wait:(BOOL)waitFlag;
  77. - mainThreadPerform:(SEL)aSelector with:anArg wait:(BOOL)waitFlag;
  78. - mainThreadPerform:(SEL)aSelector with:anArg0 with:anArg1 wait:(BOOL)waitFlag;
  79. //  This method will cause aSelector to be executed by the main thread.  If the calling
  80. //  thread is not the main thread, this method sends an aSelector message through a Mach
  81. //  port to the main thread to be executed.  If the calling thread is the main thread,
  82. //  then the aSelector message is sent directly.  If waitFlag is true, then the calling
  83. //  thread will be suspended until the main thread completes the execution of the message,
  84. //  and the return value will be that of the aSelector message executed from the main
  85. //  thread.  If waitFlag is false, then this method returns (id)nil.
  86. //  Macros: _cmdPERFORM(anArg)      /* [self mainThreadPerform:_cmd with:anArg wait:NO]   */
  87. //          _cmdPERFORMw(anArg)     /* [self mainThreadPerform:_cmd with:anArg wait:YES]  */
  88. //          _cmdINVOKE(anArg)       /* { if (!isMainTHREAD) return _cmdPERFORM(anArg); }  */
  89. //          _cmdINVOKEw(anArg)      /* { if (!isMainTHREAD) return _cmdPERFORMw(anArg); } */
  90. //
  91. //  Note on use of _cmdINVOKE(anArg) and _cmdINVOKEw(anArg) :
  92. //    To guarentee that a method is executed from the main thread the method need only 
  93. //    include '_cmdINVOKE(anArg);' at the beginning of the method.  When this macro is
  94. //    executed, it checks to see if it is the main thread.  If it is not then it is sent
  95. //    to the main thread and the macro causes the method to return.  If it is executed
  96. //    from the main thread, as it would be after being sent to _cmdPERFORM(anArg), then
  97. //    the method is allowed to execute normally.  Using _cmdINVOKEw(anArg) performs
  98. //    the same as _cmdINVOKE(anArg) except that it waits for the main thread to finish
  99. //    execution of the method before returning.  It is important to note that if this
  100. //    method is implemented in a subclass, it is important that the subclass implementation
  101. //    duplicate the the call to the macro at the beginning of the method.  Otherwise
  102. //    unpredictable results may occur.
  103. //
  104. //  Example use of _cmdINVOKE(anArg);
  105. //      - setButtonState:(BOOL)newState
  106. //      {
  107. //          _cmdINVOKE(newState);
  108. //          [myButton setState:newState];
  109. //          // ... other code here ...
  110. //          return self;
  111. //      }
  112. // 
  113. // -------------------------------------------------------------------------------------
  114. - (cthread_t)forkPerform:(SEL)aSelector detach:(BOOL)detach;
  115. - (cthread_t)forkPerform:(SEL)aSelector with:anArg detach:(BOOL)detach;
  116. - (cthread_t)forkPerform:(SEL)aSelector with:anArg0 with:anArg1 detach:(BOOL)detach;
  117. //  This method creates a new thread in which the aSelector message is executed.  The
  118. //  cthread handle for the created thread is returned if 'detach:NO' was specified, and
  119. //  normal cthread functions may be performed on this handle.  Nil is returned if
  120. //  'detach:YES' was specified, since there is no guarantee that the returned value would
  121. //  ever be valid (ie. The thread could terminate before you use the handle).
  122. //   
  123. // -------------------------------------------------------------------------------------
  124. @end
  125.