annotate Implab.Fx/StaApartment.cs @ 238:bdfdba6b645b v2

fixed unpredictable Safe.Dispose behaviour
author cin
date Fri, 01 Dec 2017 01:28:56 +0300
parents 3eb3255d8cc5
children cbe10ac0731e
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
210
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
1 using Implab.Components;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
2 using Implab.Diagnostics;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
3 using Implab.Parallels;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
4 using System;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
5 using System.Collections.Generic;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
6 using System.Linq;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
7 using System.Text;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
8 using System.Threading;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
9 using System.Threading.Tasks;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
10 using System.Windows.Forms;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
11
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
12 namespace Implab.Fx {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
13 public class StaApartment : RunnableComponent {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
14 readonly Thread m_worker;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
15 SynchronizationContext m_syncContext;
211
3eb3255d8cc5 Code review, added a non generic version of SyncContextPromise
cin
parents: 210
diff changeset
16 SyncContextPromise m_enterPromise;
3eb3255d8cc5 Code review, added a non generic version of SyncContextPromise
cin
parents: 210
diff changeset
17
210
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
18 readonly Promise m_threadStarted;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
19 readonly Promise m_threadTerminated;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
20
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
21 public StaApartment() : base(true) {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
22 m_threadStarted = new Promise();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
23 m_threadTerminated = new Promise();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
24
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
25 m_worker = new Thread(WorkerEntry);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
26 m_worker.SetApartmentState(ApartmentState.STA);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
27 m_worker.IsBackground = true;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
28 m_worker.Name = "STA managed aparment";
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
29 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
30
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
31 public SynchronizationContext SyncContext {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
32 get {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
33 if (m_syncContext == null)
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
34 throw new InvalidOperationException();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
35 return m_syncContext;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
36 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
37 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
38
211
3eb3255d8cc5 Code review, added a non generic version of SyncContextPromise
cin
parents: 210
diff changeset
39 /// <summary>
3eb3255d8cc5 Code review, added a non generic version of SyncContextPromise
cin
parents: 210
diff changeset
40 /// Returns the promise which will dispatch all handlers inside the apartment using it's <see cref="SynchronizationContext"/>
3eb3255d8cc5 Code review, added a non generic version of SyncContextPromise
cin
parents: 210
diff changeset
41 /// </summary>
3eb3255d8cc5 Code review, added a non generic version of SyncContextPromise
cin
parents: 210
diff changeset
42 /// <remarks>
3eb3255d8cc5 Code review, added a non generic version of SyncContextPromise
cin
parents: 210
diff changeset
43 /// Current implementation is optimized and will lost aync operation stack
3eb3255d8cc5 Code review, added a non generic version of SyncContextPromise
cin
parents: 210
diff changeset
44 /// </remarks>
3eb3255d8cc5 Code review, added a non generic version of SyncContextPromise
cin
parents: 210
diff changeset
45 /// <returns>The promise</returns>
3eb3255d8cc5 Code review, added a non generic version of SyncContextPromise
cin
parents: 210
diff changeset
46 public IPromise Enter() {
3eb3255d8cc5 Code review, added a non generic version of SyncContextPromise
cin
parents: 210
diff changeset
47 if (m_enterPromise == null)
3eb3255d8cc5 Code review, added a non generic version of SyncContextPromise
cin
parents: 210
diff changeset
48 throw new InvalidOperationException();
3eb3255d8cc5 Code review, added a non generic version of SyncContextPromise
cin
parents: 210
diff changeset
49 return m_enterPromise;
3eb3255d8cc5 Code review, added a non generic version of SyncContextPromise
cin
parents: 210
diff changeset
50 }
3eb3255d8cc5 Code review, added a non generic version of SyncContextPromise
cin
parents: 210
diff changeset
51
210
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
52 public IPromise Invoke(Action<ICancellationToken> action) {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
53 Safe.ArgumentNotNull(action, "action");
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
54
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
55 if (m_syncContext == null)
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
56 throw new InvalidOperationException();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
57 var p = new Promise();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
58 var lop = TraceContext.Instance.CurrentOperation;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
59
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
60 m_syncContext.Post(x => {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
61 TraceContext.Instance.EnterLogicalOperation(lop, false);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
62 try {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
63 if (p.CancelOperationIfRequested())
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
64 return;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
65
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
66 action(p);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
67 p.Resolve();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
68 } catch (Exception e) {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
69 p.Reject(e);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
70 } finally {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
71 TraceContext.Instance.Leave();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
72 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
73 }, null);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
74
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
75 return p;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
76 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
77
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
78 public IPromise<T> Invoke<T>(Func<ICancellationToken, T> action) {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
79 Safe.ArgumentNotNull(action, "action");
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
80
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
81 if (m_syncContext == null)
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
82 throw new InvalidOperationException();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
83 var p = new Promise<T>();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
84 var lop = TraceContext.Instance.CurrentOperation;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
85
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
86 m_syncContext.Post(x => {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
87 TraceContext.Instance.EnterLogicalOperation(lop, false);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
88 try {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
89 if (p.CancelOperationIfRequested())
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
90 return;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
91 p.Resolve(action(p));
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
92 } catch (Exception e) {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
93 p.Reject(e);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
94 } finally {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
95 TraceContext.Instance.Leave();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
96 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
97 }, null);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
98
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
99 return p;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
100 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
101
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
102 public IPromise Invoke(Action action) {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
103 Safe.ArgumentNotNull(action, "action");
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
104
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
105 if (m_syncContext == null)
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
106 throw new InvalidOperationException();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
107 var p = new Promise();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
108 var lop = TraceContext.Instance.CurrentOperation;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
109
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
110 m_syncContext.Post(x => {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
111 TraceContext.Instance.EnterLogicalOperation(lop, false);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
112 try {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
113 if (p.CancelOperationIfRequested())
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
114 return;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
115 action();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
116 p.Resolve();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
117 } catch (Exception e) {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
118 p.Reject(e);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
119 } finally {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
120 TraceContext.Instance.Leave();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
121 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
122 }, null);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
123
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
124 return p;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
125 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
126
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
127 public IPromise<T> Invoke<T>(Func<T> action) {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
128 Safe.ArgumentNotNull(action, "action");
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
129
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
130 if (m_syncContext == null)
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
131 throw new InvalidOperationException();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
132 var p = new Promise<T>();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
133 var lop = TraceContext.Instance.CurrentOperation;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
134
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
135 m_syncContext.Post(x => {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
136 TraceContext.Instance.EnterLogicalOperation(lop, false);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
137 try {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
138 if (p.CancelOperationIfRequested())
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
139 return;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
140 p.Resolve(action());
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
141 } catch (Exception e) {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
142 p.Reject(e);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
143 } finally {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
144 TraceContext.Instance.Leave();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
145 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
146 }, null);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
147
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
148 return p;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
149 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
150
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
151
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
152 /// <summary>
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
153 /// Starts the apartment thread
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
154 /// </summary>
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
155 /// <returns>Promise which will be fullfiled when the syncronization
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
156 /// context will be ready to accept tasks.</returns>
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
157 protected override IPromise OnStart() {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
158 m_worker.Start();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
159 return m_threadStarted;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
160 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
161
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
162 /// <summary>
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
163 /// Posts quit message to the message loop of the apartment
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
164 /// </summary>
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
165 /// <returns>Promise</returns>
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
166 protected override IPromise OnStop() {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
167 m_syncContext.Post(x => Application.ExitThread(), null);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
168 return m_threadTerminated;
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
169 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
170
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
171 void WorkerEntry() {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
172 m_syncContext = new WindowsFormsSynchronizationContext();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
173 SynchronizationContext.SetSynchronizationContext(m_syncContext);
211
3eb3255d8cc5 Code review, added a non generic version of SyncContextPromise
cin
parents: 210
diff changeset
174 m_enterPromise = new SyncContextPromise(m_syncContext);
210
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
175 m_threadStarted.Resolve();
211
3eb3255d8cc5 Code review, added a non generic version of SyncContextPromise
cin
parents: 210
diff changeset
176 m_enterPromise.Resolve();
210
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
177
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
178 Application.OleRequired();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
179 Application.Run();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
180
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
181 try {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
182 OnShutdown();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
183 m_threadTerminated.Resolve();
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
184 } catch(Exception err) {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
185 m_threadTerminated.Reject(err);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
186 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
187 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
188
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
189 /// <summary>
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
190 /// Called from the STA apartment after the message loop is terminated, override this
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
191 /// method to handle apartment cleanup.
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
192 /// </summary>
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
193 protected virtual void OnShutdown() {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
194 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
195
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
196 protected override void Dispose(bool disposing) {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
197 if (disposing) {
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
198 if (!m_threadTerminated.IsResolved)
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
199 m_syncContext.Post(x => Application.ExitThread(), null);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
200 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
201 base.Dispose(disposing);
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
202 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
203 }
5dc21f6a3222 Code review for RunnableComponent
cin
parents:
diff changeset
204 }