Fixed documentation of Waitable and Request classes; wrote down some ideas to improve the request framework
git-svn-id: file:///srv/devel/repo-conversion/nusu@75 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
		
							parent
							
								
									73ef5de576
								
							
						
					
					
						commit
						e0cf91a0a4
					
				
					 4 changed files with 88 additions and 21 deletions
				
			
		
							
								
								
									
										68
									
								
								Documents/Request Framework.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								Documents/Request Framework.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,68 @@ | |||
| The request framework should not require that .NET multithreading is used for | ||||
| asynchronous requests. | ||||
| 
 | ||||
| Otherwise, it would prvent overlapped operations, 3rd party APIs (eg. used | ||||
| via P/Invoke) from being able to use the request framework and possibly even | ||||
| spawn duplicate implementations. | ||||
| 
 | ||||
| 
 | ||||
| Design using interfaces: | ||||
| 
 | ||||
|   interface IWaitable { | ||||
| 
 | ||||
|     /// <summary>Fired when the background process has finished</summary> | ||||
|     /// <remarks> | ||||
|     ///   If the process is already finished when a client registers to this event, | ||||
|     ///   the registered callback will be invoked synchronously right when the | ||||
|     ///   registration takes place. | ||||
|     /// </remarks> | ||||
|     event EventHandler Finished; | ||||
| 
 | ||||
|     /// <summary>Waits until the background process finishes</summary> | ||||
|     void Wait(); | ||||
| 
 | ||||
|     /// <summary>Waits until the background process finishes or a timeout occurs</summary> | ||||
|     /// <param name="timeoutMilliseconds"> | ||||
|     ///   Number of milliseconds after which to stop waiting and return immediately | ||||
|     /// </param> | ||||
|     /// <returns> | ||||
|     ///   True if the background process completed, false if the timeout was reached | ||||
|     /// </returns> | ||||
|     bool Wait(int timeoutMilliseconds); | ||||
| 
 | ||||
|     /// <summary>Whether the background process has finished</summary> | ||||
|     bool Finished { get; } | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   interface IThreadedWaitable : IWaitable { | ||||
| 
 | ||||
|     WaitHandle WaitHandle { get; } | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   interface IRequest : IWaitable { | ||||
| 
 | ||||
|     /// <summary> | ||||
|     ///   Waits for the background process to complete and re-throws the exception to | ||||
|     ///   the caller when an error has occured | ||||
|     /// </summary> | ||||
|     void Join(); | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   interface IRequest<ResultType> : IRequest { | ||||
| 
 | ||||
|     /// <summary> | ||||
|     ///   Waits for the background process to complete and re-throws the exception to | ||||
|     ///   the caller when an error has occured | ||||
|     /// </summary> | ||||
|     /// <returns>The result of the background processing</returns> | ||||
|     new ResultType Join(); | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   interface IThreadedRequest : IRequest, IThreadedWaitable { } | ||||
| 
 | ||||
|   interface IThreadedRequest<ResultType> : | ||||
|     IRequest<ResultType>, IThreadedRequest, IThreadedWaitable { } | ||||
|  | @ -217,6 +217,7 @@ | |||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <Content Include="Documents\Nuclex.Support.txt" /> | ||||
|     <Content Include="Documents\Request Framework.txt" /> | ||||
|   </ItemGroup> | ||||
|   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> | ||||
|   <Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\v3.0\Microsoft.Xna.GameStudio.Common.targets" /> | ||||
|  |  | |||
|  | @ -70,7 +70,7 @@ namespace Nuclex.Support.Tracking { | |||
|     /// <returns> | ||||
|     ///   A failed request that reports the provided exception as cause for its failure | ||||
|     /// </returns> | ||||
|     public static Request CreateFailedDummyRequest(Exception exception) { | ||||
|     public static Request CreateFailedDummy(Exception exception) { | ||||
|       return new EndedDummyRequest(exception); | ||||
|     } | ||||
| 
 | ||||
|  | @ -134,7 +134,7 @@ namespace Nuclex.Support.Tracking { | |||
|     /// <returns> | ||||
|     ///   A failed request that reports the provided exception as cause for its failure | ||||
|     /// </returns> | ||||
|     public static new Request CreateFailedDummyRequest(Exception exception) { | ||||
|     public static new Request CreateFailedDummy(Exception exception) { | ||||
|       return new EndedDummyRequest(exception); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,9 +23,7 @@ using System.Threading; | |||
| 
 | ||||
| namespace Nuclex.Support.Tracking { | ||||
| 
 | ||||
|   /// <summary> | ||||
|   ///   Base class for actions on which that give an indication of their progress | ||||
|   /// </summary> | ||||
|   /// <summary>Base class for background processes the user can wait on</summary> | ||||
|   /// <remarks> | ||||
|   ///   <para> | ||||
|   ///     By encapsulating long-running operations which will ideally be running in | ||||
|  | @ -40,27 +38,27 @@ namespace Nuclex.Support.Tracking { | |||
|   ///     task has completed. This class deliberately does not provide an Execute() | ||||
|   ///     method or anything similar to clearly seperate the initiation of an operation | ||||
|   ///     from just monitoring it. By omitting an Execute() method, it also becomes | ||||
|   ///     possible to construct a progression just-in-time when it is explicitely being | ||||
|   ///     possible to construct a Waitable just-in-time when it is explicitely being | ||||
|   ///     asked for. | ||||
|   ///   </para> | ||||
|   /// </remarks> | ||||
|   public abstract class Waitable { | ||||
| 
 | ||||
|     #region class EndedDummyProgression | ||||
|     #region class EndedDummyWaitable | ||||
| 
 | ||||
|     /// <summary>Dummy progression which always is in the 'ended' state</summary> | ||||
|     /// <summary>Dummy waitable which always is in the 'ended' state</summary> | ||||
|     private class EndedDummyWaitable : Waitable { | ||||
| 
 | ||||
|       /// <summary>Initializes a new ended dummy progression</summary> | ||||
|       /// <summary>Initializes a new ended dummy waitable</summary> | ||||
|       public EndedDummyWaitable() { | ||||
|         OnAsyncEnded(); | ||||
|       } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     #endregion // class EndedDummyProgression | ||||
|     #endregion // class EndedDummyWaitable | ||||
| 
 | ||||
|     /// <summary>A dummy progression that's always in the 'ended' state</summary> | ||||
|     /// <summary>A dummy waitable that's always in the 'ended' state</summary> | ||||
|     /// <remarks> | ||||
|     ///   Useful if an operation is already complete when it's being asked for or | ||||
|     ///   when a progression that's lazily created is accessed after the original | ||||
|  | @ -68,15 +66,15 @@ namespace Nuclex.Support.Tracking { | |||
|     /// </remarks> | ||||
|     public static readonly Waitable EndedDummy = new EndedDummyWaitable(); | ||||
| 
 | ||||
|     /// <summary>Will be triggered when the progression has ended</summary> | ||||
|     /// <summary>Will be triggered when the Waitable has ended</summary> | ||||
|     public event EventHandler AsyncEnded; | ||||
| 
 | ||||
|     /// <summary>Whether the progression has ended already</summary> | ||||
|     /// <summary>Whether the Waitable has ended already</summary> | ||||
|     public bool Ended { | ||||
|       get { return this.ended; } | ||||
|     } | ||||
| 
 | ||||
|     /// <summary>WaitHandle that can be used to wait for the progression to end</summary> | ||||
|     /// <summary>WaitHandle that can be used to wait for the Waitable to end</summary> | ||||
|     public WaitHandle WaitHandle { | ||||
|       get { | ||||
| 
 | ||||
|  | @ -87,11 +85,11 @@ namespace Nuclex.Support.Tracking { | |||
|         // We can *not* optimize this lock away since we absolutely must not create | ||||
|         // two doneEvents -- someone might call .WaitOne() on the first one when only | ||||
|         // the second one is referenced by this.doneEvent and thus gets set in the end. | ||||
|         if (this.doneEvent == null) { | ||||
|         if(this.doneEvent == null) { | ||||
| 
 | ||||
|           lock (this) { | ||||
|           lock(this) { | ||||
| 
 | ||||
|             if (this.doneEvent == null) | ||||
|             if(this.doneEvent == null) | ||||
|               this.doneEvent = new ManualResetEvent(this.ended); | ||||
| 
 | ||||
|           } | ||||
|  | @ -121,13 +119,13 @@ namespace Nuclex.Support.Tracking { | |||
|       // Make sure the progression is not ended more than once. By guaranteeing that | ||||
|       // a progression can only be ended once, we allow users of this class to | ||||
|       // skip some safeguards against notifications arriving twice. | ||||
|       lock (this) { | ||||
|       lock(this) { | ||||
| 
 | ||||
|         // No double lock here, this is an exception that indicates an implementation | ||||
|         // error that will not be triggered under normal circumstances. We don't want | ||||
|         // to waste any effort optimizing the speed at which an implementation fault | ||||
|         // will be noticed. | ||||
|         if (this.ended) | ||||
|         if(this.ended) | ||||
|           throw new InvalidOperationException("The progression has already been ended"); | ||||
| 
 | ||||
|         this.ended = true; | ||||
|  | @ -137,12 +135,12 @@ namespace Nuclex.Support.Tracking { | |||
|       // Doesn't need a lock. If another thread wins the race and creates the event | ||||
|       // after we just saw it being null, it would be created in an already set | ||||
|       // state due to the ended flag (see above) being set to true beforehand! | ||||
|       if (this.doneEvent != null) | ||||
|       if(this.doneEvent != null) | ||||
|         this.doneEvent.Set(); | ||||
| 
 | ||||
|       // Finally, fire the AsyncEnded event | ||||
|       EventHandler copy = AsyncEnded; | ||||
|       if (copy != null) | ||||
|       if(copy != null) | ||||
|         copy(this, EventArgs.Empty); | ||||
| 
 | ||||
|     } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue