##// END OF EJS Templates
improved tracing...
cin -
r40:fe33f4e02ad5 default
parent child
Show More
@@ -0,0 +1,37
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5
6 namespace Implab {
7 /// <summary>
8 /// Компоненты являются состовными объектами, имеют детерминированный период жизни, автоматически освобождают ресурсы входящие в них.
9 /// </summary>
10 /// <remarks>Компонента управляет временем жизни включенных в нее компонент</remarks>
11 public class Component: Disposable {
12 LinkedList<IDisposable> m_components = new LinkedList<IDisposable>();
13
14 /// <summary>
15 /// Коллекция компонент, из которых состоит текущая компонента.
16 /// </summary>
17 public ICollection<IDisposable> Components {
18 get {
19 AssertNotDisposed();
20 return m_components;
21 }
22 }
23
24 /// <summary>
25 /// Освобождает компоненты, входящие в состав текущей компоненты.
26 /// </summary>
27 /// <param name="disposing">Признак того, что происходит освобождение ресурсов.</param>
28 protected override void Dispose(bool disposing) {
29 if (disposing) {
30 foreach (var item in m_components)
31 item.Dispose();
32 m_components.Clear();
33 }
34 base.Dispose(disposing);
35 }
36 }
37 } No newline at end of file
@@ -0,0 +1,12
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace Implab.Diagnostics {
7 public struct EventText {
8 public int indent;
9
10 public string content;
11 }
12 }
@@ -0,0 +1,10
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace Implab.Diagnostics {
7 public interface IEventTextFormatter<in TEvent> {
8 EventText Format(TraceContext context, TEvent data);
9 }
10 }
@@ -0,0 +1,44
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using System.Text;
6
7 namespace Implab.Diagnostics {
8 public class TextFileListener: TextListenerBase {
9 readonly TextWriter m_textWriter;
10
11 public TextFileListener(string fileName) {
12 m_textWriter = File.CreateText(fileName);
13
14 m_textWriter.WriteLine("LOG {0}", DateTime.Now);
15 Register(this);
16 }
17
18 protected override void WriteEntry(TraceContext context, EventText text) {
19 var msg = new StringBuilder();
20 for (int i = 0; i < text.indent; i++)
21 msg.Append(" ");
22 msg.AppendFormat("[{0}]: {1}", context.ThreadId, text.content);
23
24 lock (m_textWriter) {
25 if (!IsDisposed) {
26 m_textWriter.WriteLine(msg.ToString());
27 m_textWriter.Flush();
28 }
29 }
30 }
31
32
33 protected override void Dispose(bool disposing) {
34 base.Dispose(disposing);
35 if (disposing) {
36 lock (m_textWriter) {
37 Safe.Dispose(m_textWriter);
38 }
39 }
40 }
41
42
43 }
44 }
@@ -0,0 +1,99
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace Implab.Diagnostics {
7 public abstract class TextListenerBase : ServiceLocator, IEventTextFormatter<object>, IEventTextFormatter<TraceEvent> {
8
9 readonly Dictionary<object, Action> m_subscriptions = new Dictionary<object, Action>();
10
11 protected TextListenerBase() {
12 Register(this);
13 }
14
15 public void Subscribe(Type eventType) {
16 if (eventType == null)
17 throw new ArgumentNullException("eventType");
18 GetType().GetMethod("Subscribe", new Type[0]).MakeGenericMethod(eventType).Invoke(this, null);
19 }
20
21 public void Subscribe<TEvent>() {
22 Subscribe<TEvent>(LogChannel<TEvent>.Default);
23 }
24
25 public void Subscribe<TEvent>(LogChannel<TEvent> channel) {
26 if (channel == null)
27 throw new ArgumentNullException("channel");
28
29 lock (m_subscriptions) {
30 AssertNotDisposed();
31
32 var formatter = GetService<IEventTextFormatter<TEvent>>();
33
34 EventHandler<ValueEventArgs<TEvent>> handler = (sender, args) => {
35 WriteEntry((TraceContext)sender, formatter.Format((TraceContext)sender, args.Value));
36 };
37
38 if (m_subscriptions.ContainsKey(channel))
39 return;
40
41 channel.Events += handler;
42
43 Action unsubscribe = () => {
44 channel.Events -= handler;
45 };
46
47 m_subscriptions.Add(channel, unsubscribe);
48 }
49 }
50
51 public void Unsubscribe<TEvent>(LogChannel<TEvent> channel) {
52 if (channel == null)
53 throw new ArgumentNullException("channel");
54
55 lock (m_subscriptions) {
56 Action subscription;
57 if (m_subscriptions.TryGetValue(channel, out subscription)) {
58 subscription();
59 m_subscriptions.Remove(channel);
60 }
61 }
62 }
63
64 public void UnsubscribeAll() {
65 lock (m_subscriptions) {
66 foreach (var subscription in m_subscriptions.Values)
67 subscription();
68 m_subscriptions.Clear();
69 }
70 }
71
72 protected abstract void WriteEntry(TraceContext context, EventText text);
73
74 public EventText Format(TraceContext context, object data) {
75 return new EventText {
76 indent = context.CurrentOperation.Level,
77 content = data.ToString()
78 };
79 }
80
81 public EventText Format(TraceContext context, TraceEvent data) {
82 var level = context.CurrentOperation.Level;
83 if (data.EventType == TraceEventType.OperationCompleted || data.EventType == TraceEventType.OperationStarted)
84 level--;
85
86 return new EventText {
87 indent = level,
88 content = data.ToString()
89 };
90 }
91
92 protected override void Dispose(bool disposing) {
93 if (disposing) {
94 UnsubscribeAll();
95 }
96 base.Dispose(disposing);
97 }
98 }
99 }
@@ -0,0 +1,46
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Linq;
5 using System.Web;
6
7 namespace Implab {
8 public class Disposable : IDisposable {
9
10 bool m_disposed;
11
12 public event EventHandler Disposed;
13
14 public bool IsDisposed {
15 get { return m_disposed; }
16 }
17
18 protected void AssertNotDisposed() {
19 if (m_disposed)
20 throw new ObjectDisposedException(this.ToString());
21 }
22
23 protected virtual void Dispose(bool disposing) {
24 if (disposing && !m_disposed) {
25 m_disposed = true;
26
27 EventHandler temp = Disposed;
28 if (temp != null)
29 temp(this,EventArgs.Empty);
30 }
31 }
32 public void Dispose() {
33 Dispose(true);
34 GC.SuppressFinalize(this);
35 }
36
37 protected virtual void ReportObjectLeaks() {
38 Trace.TraceWarning("The object is marked as disposable but isn't disposed properly: {0}", this);
39 }
40
41 ~Disposable() {
42 Dispose(false);
43 ReportObjectLeaks();
44 }
45 }
46 } No newline at end of file
@@ -0,0 +1,12
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Implab {
8 public interface IServiceLocator: IServiceProvider {
9 T GetService<T>();
10 bool TryGetService<T>(out T service);
11 }
12 }
@@ -0,0 +1,209
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5
6 namespace Implab {
7 /// <summary>
8 /// Коллекция сервисов, позволяет регистрировать и получать сервисы.
9 /// </summary>
10 public class ServiceLocator: Component, IServiceLocator, IServiceProvider {
11 // запись об сервисе
12 struct ServiceEntry {
13 public object service; // сервис
14 public bool shared; // признак того, что сервис НЕ нужно освобождать
15 public Func<object> activator; // активатор сервиса при первом обращении
16 public List<Type> associated; // ссылки на текущую запись
17 public Type origin; // ссылка на оригинальную запись о сервисе
18 }
19
20 // словарь существующих сервисов
21 Dictionary<Type, ServiceEntry> m_services = new Dictionary<Type,ServiceEntry>();
22
23 /// <summary>
24 /// Получает объект предоставляющий сервис <typeparamref name="T"/>.
25 /// </summary>
26 /// <typeparam name="T">Тип запрашиваемого сервиса</typeparam>
27 /// <returns>Объект, реализующий сервис</returns>
28 /// <exception cref="KeyNotFoundException">Сервис не зарегистрирован</exception>
29 public T GetService<T>() {
30 return (T)GetService(typeof(T));
31 }
32
33
34 /// <summary>
35 /// Пытается получить указанный сервис, в случае, если компонента не предоставляет требуемый сервис
36 /// не возникает исключений.
37 /// </summary>
38 /// <typeparam name="T">Тип требуемого сервиса.</typeparam>
39 /// <param name="service">Объект реализующий сервис, или <c>default(T)</c> если такового нет.</param>
40 /// <returns><c>true</c> - сервис найден, <c>false</c> - сервис не зарегистрирован.</returns>
41 public bool TryGetService<T>(out T service) {
42 AssertNotDisposed();
43
44 try {
45 service = GetService<T>();
46 return true;
47 } catch(KeyNotFoundException) {
48 service = default(T);
49 return false;
50 }
51 }
52
53 /// <summary>
54 /// Получает объект предоставляющий сервис <paramref name="serviceType"/>
55 /// </summary>
56 /// <param name="serviceType">Тип запрашиваемого сервиса</param>
57 /// <returns>Объект, реализующий сервис</returns>
58 /// <exception cref="KeyNotFoundException">Сервис не зарегистрирован</exception>
59 public object GetService(Type serviceType) {
60 if (serviceType == null)
61 throw new ArgumentNullException("serviceType");
62 AssertNotDisposed();
63
64 ServiceEntry se;
65 if (!m_services.TryGetValue(serviceType, out se)) {
66 // ищем ближайщий объект, реализующий нужный сервис
67 Type pt = null;
68 foreach (var t in m_services.Keys)
69 if (serviceType.IsAssignableFrom(t) && (pt == null || t.IsAssignableFrom(pt)))
70 pt = t;
71 if (pt == null)
72 throw new ApplicationException(String.Format("{0} doesn't provide {1} service",this,serviceType));
73
74 var pe = m_services[pt];
75
76 // найденная запись может ссылаться на оригинальную запись с сервисом
77 if(pe.origin != null) {
78 pt = pe.origin;
79 pe = m_services[pt];
80 }
81
82 // добавляем список с обратными ссылками
83 if (pe.associated == null)
84 pe.associated = new List<Type>();
85
86 pe.associated.Add(serviceType);
87
88 // обновляем родительскую запись
89 m_services[pt] = pe;
90
91 // создаем запись со ссылкой
92 se = new ServiceEntry {
93 service = pe.service,
94 origin = pt,
95 shared = true // предотвращаем множественные попытки освобождения
96 };
97
98 m_services[serviceType] = se;
99 }
100
101 // запись содержит в себе информацию о сервисе
102 if (se.service != null)
103 return se.service;
104
105 // текущая запись является ссылкой
106 if (se.origin != null) {
107 se.service = GetService(se.origin);
108 m_services[serviceType] = se;
109 return se.service;
110 }
111
112 // текущая запись не является ссылкой и не имеет информации о сервисе
113 // она должна сожержать информацию об активации
114 if (se.activator != null) {
115 se.service = se.activator();
116
117 m_services[serviceType] = se;
118
119 return se.service;
120 }
121
122 throw new Exception("Unable to create a service instance");
123 }
124
125 /// <summary>
126 /// Регистрирует фабрику для активации сервиса по первому требованию.
127 /// </summary>
128 /// <typeparam name="T">Тип регистрируемого сервиса.</typeparam>
129 /// <param name="activator">Фабрика для создания/получения объекта, предоставляющего сервис.</param>
130 /// <exception cref="InvalidOperationException">Указанный сервис уже зарегистрирован.</exception>
131 /// <remarks>При освобождении сервис-локатора, сервисы полученные в результате активации также будут освобождены.</remarks>
132 public void Register<T>(Func<T> activator) {
133 if (activator == null)
134 throw new ArgumentNullException("activator");
135
136 AssertNotDisposed();
137
138 Unregister(typeof(T));
139
140 m_services[typeof(T)] = new ServiceEntry {
141 activator = () => activator() as object
142 };
143 }
144
145 /// <summary>
146 /// Регистрирует объект, предоставляющий сервис.
147 /// </summary>
148 /// <typeparam name="T">Тип регистрируемого сервиса.</typeparam>
149 /// <param name="service">Объект, предоставляющий сервис.</param>
150 /// <exception cref="InvalidOperationException">Указанный сервис уже зарегистрирован.</exception>
151 /// <remarks>Сервис-локатором не управляет временем жизни объекта для зарегистрированного сервиса.</remarks>
152 public void Register<T>(T service) {
153 Register(service, true);
154 }
155
156 /// <summary>
157 /// Регистрирует объект, предоставляющий сервис.
158 /// </summary>
159 /// <typeparam name="T">Тип регистрируемого сервиса.</typeparam>
160 /// <param name="service">Объект, предоставляющий сервис.</param>
161 /// <param name="shared">Признак того, что объект является разделяемым и сервис-локатор не должен его освобождать.</param>
162 /// <exception cref="InvalidOperationException">Указанный сервис уже зарегистрирован.</exception>
163 public void Register<T>(T service, bool shared) {
164 if (service == null)
165 throw new ArgumentNullException("service");
166
167 AssertNotDisposed();
168
169 Unregister(typeof(T));
170
171 m_services[typeof(T)] = new ServiceEntry { service = service, shared = shared };
172 }
173
174 public void Unregister(Type serviceType) {
175 if (serviceType == null)
176 throw new ArgumentNullException("serviceType");
177
178 AssertNotDisposed();
179
180 ServiceEntry se;
181 if (m_services.TryGetValue(serviceType, out se)) {
182 // освобождаем ресурсы
183 if (se.service != null && !se.shared)
184 ((IDisposable)se.service).Dispose();
185 m_services.Remove(serviceType);
186
187 // убираем связанные записи
188 if (se.associated != null)
189 foreach (var item in se.associated)
190 m_services.Remove(item);
191 }
192 }
193
194 /// <summary>
195 /// Освобождает зарегистрированные сервисы (которые требуется освобоить).
196 /// </summary>
197 /// <param name="disposing">Призанак того, что нужно освободить ресурсы.</param>
198 protected override void Dispose(bool disposing) {
199 if (disposing) {
200
201 foreach (var entry in m_services.Values)
202 if (!entry.shared && entry.service is IDisposable)
203 ((IDisposable)entry.service).Dispose();
204
205 }
206 base.Dispose(disposing);
207 }
208 }
209 } No newline at end of file
@@ -4,29 +4,16 using System.Linq;
4 4 using System.Text;
5 5
6 6 namespace Implab.Diagnostics {
7 public class ConsoleTraceListener {
7 public class ConsoleTraceListener: TextListenerBase {
8 8
9 9 static readonly object _consoleLock = new object();
10 10
11 public void Subscribe() {
12 LogChannel<TraceEvent>.Default.Events += Default_Events;
13 }
14
15 public void Unsubscribe() {
16 LogChannel<TraceEvent>.Default.Events -= Default_Events;
17 }
11 protected override void WriteEntry(TraceContext context, EventText text) {
12 var msg = new StringBuilder();
18 13
19 void Default_Events(object sender, ValueEventArgs<TraceEvent> e) {
20 LogEvent((TraceContext)sender, e.Value);
21 }
22
23 void LogEvent(TraceContext context, TraceEvent evt) {
24 var msg = new StringBuilder();
25 for (int i = 0; i < context.CurrentOperation.Level; i++)
14 for (int i = 0; i < text.indent; i++)
26 15 msg.Append(" ");
27 msg.Append(evt.EventType);
28 msg.AppendFormat("[{0}]: ",context.ThreadId);
29 msg.Append(evt.Message);
16 msg.AppendFormat("[{0}]: {1}", context.ThreadId, text.content);
30 17
31 18 lock (_consoleLock) {
32 19 Console.ForegroundColor = (ConsoleColor)(context.ThreadId % 15 + 1);
@@ -6,17 +6,23 using System.Threading;
6 6 using System.Threading.Tasks;
7 7
8 8 namespace Implab.Diagnostics {
9 /// <summary>
10 /// Контекст трассировки, привязывается к потоку и содержит в себе информацию о стеке логических операций.
11 /// </summary>
12 /// <remarks>
13 /// Контекст трассировки передается слушателям событий для определения места, где возникло событие.
14 /// </remarks>
9 15 public class TraceContext {
10 16 LogicalOperation m_currentOperation;
11 readonly LogicalOperation m_traceBound;
17 readonly LogicalOperation m_bound;
12 18 readonly int m_threadId;
13 readonly TraceContext m_parent;
14
15 readonly static object _consoleLock = new object();
16 19
17 20 [ThreadStatic]
18 21 static TraceContext _current;
19 22
23 /// <summary>
24 /// Текущий контекст трассировки для потока, создается астоматически при первом обращении.
25 /// </summary>
20 26 public static TraceContext Current {
21 27 get {
22 28 if (_current == null)
@@ -29,64 +35,124 namespace Implab.Diagnostics {
29 35 if (context == null)
30 36 throw new ArgumentNullException("context");
31 37
32 m_parent = context;
33 38 m_currentOperation = context.CurrentOperation;
34 m_traceBound = context.CurrentOperation;
39 m_bound = context.CurrentOperation;
35 40 m_threadId = Thread.CurrentThread.ManagedThreadId;
36
37 LogEvent(TraceEventType.Transfer, "FORK {0}", context.ThreadId);
38 41 }
39 42
40 43 TraceContext() {
41 44 m_currentOperation = new LogicalOperation();
42 m_traceBound = m_currentOperation;
45 m_bound = m_currentOperation;
43 46 m_threadId = Thread.CurrentThread.ManagedThreadId;
44 47 }
45 48
49 /// <summary>
50 /// При необходимости копирует состояние контекста трассивровки в текущий поток.
51 /// </summary>
52 /// <param name="from">Исходный контекст трассировки, который передается.</param>
53 /// <remarks>
54 /// <para>
55 /// Копирование происходит за счет создания нового контекста трассировки и заполнением его
56 /// состояния из переданного контекста. При этом копируется стек операций, однако в новом
57 /// контексте ранее начатые логические операции не могут быть завершены.
58 /// </para>
59 /// <para>
60 /// Если передача состояния состоялась, то вызывается событие трассировки <see cref="TraceEventType.Transfer"/>.
61 /// </para>
62 /// </remarks>
46 63 public static void Transfer(TraceContext from) {
47 _current = from == null ? new TraceContext() : new TraceContext(from);
48 }
49
50 public TraceContext ParentContext {
51 get {
52 return m_parent;
64 if (_current == from)
65 return;
66 if (from != null) {
67 var context = new TraceContext(from);
68 context.LogEvent(TraceEventType.Transfer, "[{0}]-->[{1}]",from.ThreadId, context.ThreadId);
69 _current = context;
70 } else {
71 _current = new TraceContext();
53 72 }
54 73 }
55 74
75 /// <summary>
76 /// Создает постоянную копию текущего контекста, данную копию можно хранить и использовать для передачи через <see cref="Transfer(TraceContext)"/>
77 /// </summary>
78 /// <returns>Копия текущего контекста трассировки или <c>null</c> если таковой не был создан.</returns>
79 public static TraceContext Snapshot() {
80 return _current == null ? null : new TraceContext(_current);
81 }
82
83 /// <summary>
84 /// Выполняет переданное действие в указанном контексте трассировки, по окончании восстанавливает предыдущий контекст трассировки потока.
85 /// </summary>
86 /// <param name="action"></param>
87 public void Invoke(Action action) {
88 if (action == null)
89 throw new ArgumentNullException("action");
90 var old = _current;
91 Transfer(this);
92 try {
93 action();
94 } finally {
95 _current = old;
96 }
97 }
98
99 /// <summary>
100 /// Текущая логическая операция.
101 /// </summary>
56 102 public LogicalOperation CurrentOperation {
57 103 get {
58 104 return m_currentOperation;
59 105 }
60 106 }
61 107
62 public LogicalOperation TraceBound {
108 /// <summary>
109 /// Операция ниже которой нельзя опускаться в стеке логических операций, т.е. она не может быть завершена в текущем контексте.
110 /// </summary>
111 public LogicalOperation BoundOperation {
63 112 get {
64 return m_traceBound;
113 return m_bound;
65 114 }
66 115 }
67 116
117 /// <summary>
118 /// Поток, в котором создан контекст трассировки.
119 /// </summary>
68 120 public int ThreadId {
69 121 get {
70 122 return m_threadId;
71 123 }
72 124 }
73 125
126 /// <summary>
127 /// Начинает безымянную логическую операцию.
128 /// </summary>
74 129 public void StartLogicalOperation() {
75 130 StartLogicalOperation(null);
76 131 }
77 132
133 /// <summary>
134 /// Начинает логическую операцию с указанным именем. Созданная операция будет добвалена в стек логических операций контекста, затем будет создано соответсвующее событие.
135 /// </summary>
136 /// <param name="name">Имя начинаемой операции.</param>
78 137 public void StartLogicalOperation(string name) {
79 LogEvent(TraceEventType.OperationStarted, "{0}", name);
80 138 m_currentOperation = new LogicalOperation(name, m_currentOperation);
139 LogEvent(TraceEventType.OperationStarted, name);
81 140 }
82 141
142 /// <summary>
143 /// Заканчивает логическую операцию начатую в текущем контексте. Операции, начатые в других контекстах не могут быть закончены в текущем контексте.
144 /// </summary>
145 /// <remarks>
146 /// При вызове данного метода создается событие журнала трассировки, либо о завершении операции, либо об ошибки, поскольку данная операция
147 /// начата в другом контексте.
148 /// </remarks>
83 149 public void EndLogicalOperation() {
84 if (m_traceBound == m_currentOperation) {
150 if (m_bound == m_currentOperation) {
85 151 LogEvent(TraceEventType.Error, "Trying to end the operation which isn't belongs to current trace");
86 152 } else {
87 153 var op = m_currentOperation;
154 LogEvent(TraceEventType.OperationCompleted, "{0} {1} ms", op.Name, op.Duration);
88 155 m_currentOperation = m_currentOperation.Parent;
89 LogEvent(TraceEventType.OperationCompleted, "{0} {1} ms", op.Name, op.Duration);
90 156 }
91 157 }
92 158
@@ -20,6 +20,10 namespace Implab.Diagnostics {
20 20 Message = message;
21 21 }
22 22
23 public override string ToString() {
24 return String.Format("{0}: {1}", EventType, Message);
25 }
26
23 27 public static TraceEvent Create(TraceEventType type, string format, params object[] args) {
24 28 return new TraceEvent(type, String.Format(format, args));
25 29 }
@@ -7,15 +7,12 using System.Threading.Tasks;
7 7
8 8 namespace Implab.Diagnostics {
9 9 /// <summary>
10 /// Класс для публикации событий выполнения программы, события публикуются через <see cref="LogChannel{TraceEvent}"/>
10 /// Класс для публикации событий выполнения программы, события публикуются через <see cref="LogChannel{TraceEvent}"/>.
11 /// Журнал трассировки отражает логический ход выполнения программы и существует всегда, поскольку тесно связан с
12 /// контекстом трассировки.
11 13 /// </summary>
12 14 public static class TraceLog {
13 15 [Conditional("TRACE")]
14 public static void Transfer(TraceContext from) {
15 TraceContext.Transfer(from);
16 }
17
18 [Conditional("TRACE")]
19 16 public static void StartLogicalOperation() {
20 17 TraceContext.Current.StartLogicalOperation();
21 18 }
@@ -32,24 +32,32
32 32 <Reference Include="System" />
33 33 </ItemGroup>
34 34 <ItemGroup>
35 <Compile Include="Component.cs" />
35 36 <Compile Include="Diagnostics\ConsoleTraceListener.cs" />
37 <Compile Include="Diagnostics\EventText.cs" />
38 <Compile Include="Diagnostics\IEventTextFormatter.cs" />
36 39 <Compile Include="Diagnostics\LogChannel.cs" />
37 40 <Compile Include="Diagnostics\LogicalOperation.cs" />
41 <Compile Include="Diagnostics\TextFileListener.cs" />
42 <Compile Include="Diagnostics\TextListenerBase.cs" />
38 43 <Compile Include="Diagnostics\TraceLog.cs" />
39 44 <Compile Include="Diagnostics\TraceContext.cs" />
40 45 <Compile Include="Diagnostics\TraceEvent.cs" />
41 46 <Compile Include="Diagnostics\TraceEventType.cs" />
47 <Compile Include="Disposable.cs" />
42 48 <Compile Include="ICancellable.cs" />
43 49 <Compile Include="IProgressHandler.cs" />
44 50 <Compile Include="IProgressNotifier.cs" />
45 51 <Compile Include="IPromise.cs" />
46 52 <Compile Include="IPromiseBase.cs" />
53 <Compile Include="IServiceLocator.cs" />
47 54 <Compile Include="ITaskController.cs" />
48 55 <Compile Include="ManagedPromise.cs" />
49 56 <Compile Include="Parallels\DispatchPool.cs" />
50 57 <Compile Include="Parallels\ArrayTraits.cs" />
51 58 <Compile Include="Parallels\MTQueue.cs" />
52 59 <Compile Include="Parallels\WorkerPool.cs" />
60 <Compile Include="ServiceLocator.cs" />
53 61 <Compile Include="TaskController.cs" />
54 62 <Compile Include="ProgressInitEventArgs.cs" />
55 63 <Compile Include="Properties\AssemblyInfo.cs" />
@@ -14,10 +14,10 namespace Implab.Parallels {
14 14
15 15 public static Promise<T> Invoke<T>(Func<T> func) {
16 16 var p = new Promise<T>();
17 var caller = TraceContext.Current;
17 var caller = TraceContext.Snapshot();
18 18
19 19 ThreadPool.QueueUserWorkItem(param => {
20 TraceLog.Transfer(caller);
20 TraceContext.Transfer(caller);
21 21 try {
22 22 p.Resolve(func());
23 23 } catch(Exception e) {
@@ -31,10 +31,10 namespace Implab.Parallels {
31 31 public static Promise<T> InvokeNewThread<T>(Func<T> func) {
32 32 var p = new Promise<T>();
33 33
34 var caller = TraceContext.Current;
34 var caller = TraceContext.Snapshot();
35 35
36 36 var worker = new Thread(() => {
37 TraceLog.Transfer(caller);
37 TraceContext.Transfer(caller);
38 38 try {
39 39 p.Resolve(func());
40 40 } catch (Exception e) {
@@ -42,16 +42,17 namespace Implab.Parallels {
42 42
43 43 var promise = new Promise<T>();
44 44
45 var caller = TraceContext.Current;
45 var caller = TraceContext.Snapshot();
46 46
47 47 EnqueueTask(delegate() {
48 TraceLog.Transfer(caller);
48 caller.Invoke(delegate() {
49 49 try {
50 50 promise.Resolve(task());
51 51 } catch (Exception e) {
52 52 promise.Reject(e);
53 53 }
54 54 });
55 });
55 56
56 57 return promise;
57 58 }
General Comments 0
You need to be logged in to leave comments. Login now