##// END OF EJS Templates
Слияние с interactive logger
cin -
r50:f8cbe84cfdb1 merge default
parent child
Show More
@@ -0,0 +1,77
1 <?xml version="1.0" encoding="utf-8"?>
2 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4 <PropertyGroup>
5 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7 <ProjectGuid>{1DB7DB0C-8AA9-484B-A681-33AE94038391}</ProjectGuid>
8 <OutputType>Library</OutputType>
9 <AppDesignerFolder>Properties</AppDesignerFolder>
10 <RootNamespace>Implab.Diagnostics.Interactive</RootNamespace>
11 <AssemblyName>Implab.Diagnostics.Interactive</AssemblyName>
12 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13 <FileAlignment>512</FileAlignment>
14 </PropertyGroup>
15 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
16 <DebugSymbols>true</DebugSymbols>
17 <DebugType>full</DebugType>
18 <Optimize>false</Optimize>
19 <OutputPath>bin\Debug\</OutputPath>
20 <DefineConstants>DEBUG;TRACE</DefineConstants>
21 <ErrorReport>prompt</ErrorReport>
22 <WarningLevel>4</WarningLevel>
23 </PropertyGroup>
24 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
25 <DebugType>pdbonly</DebugType>
26 <Optimize>true</Optimize>
27 <OutputPath>bin\Release\</OutputPath>
28 <DefineConstants>TRACE</DefineConstants>
29 <ErrorReport>prompt</ErrorReport>
30 <WarningLevel>4</WarningLevel>
31 </PropertyGroup>
32 <ItemGroup>
33 <Reference Include="System" />
34 <Reference Include="System.Core" />
35 <Reference Include="System.Drawing" />
36 <Reference Include="System.Windows.Forms" />
37 <Reference Include="System.Xml.Linq" />
38 <Reference Include="System.Data.DataSetExtensions" />
39 <Reference Include="Microsoft.CSharp" />
40 <Reference Include="System.Data" />
41 <Reference Include="System.Xml" />
42 </ItemGroup>
43 <ItemGroup>
44 <Compile Include="InteractiveListener.cs" />
45 <Compile Include="Properties\AssemblyInfo.cs" />
46 <Compile Include="TextStyle.cs" />
47 <Compile Include="TraceForm.cs">
48 <SubType>Form</SubType>
49 </Compile>
50 <Compile Include="TraceForm.Designer.cs">
51 <DependentUpon>TraceForm.cs</DependentUpon>
52 </Compile>
53 <Compile Include="TraceViewItem.cs" />
54 </ItemGroup>
55 <ItemGroup>
56 <ProjectReference Include="..\Implab\Implab.csproj">
57 <Project>{f550f1f8-8746-4ad0-9614-855f4c4b7f05}</Project>
58 <Name>Implab</Name>
59 </ProjectReference>
60 </ItemGroup>
61 <ItemGroup>
62 <EmbeddedResource Include="TraceForm.resx">
63 <DependentUpon>TraceForm.cs</DependentUpon>
64 </EmbeddedResource>
65 </ItemGroup>
66 <ItemGroup>
67 <None Include="Properties\DataSources\TraceViewItem.datasource" />
68 </ItemGroup>
69 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
70 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
71 Other similar extension points exist, see Microsoft.Common.targets.
72 <Target Name="BeforeBuild">
73 </Target>
74 <Target Name="AfterBuild">
75 </Target>
76 -->
77 </Project> No newline at end of file
@@ -0,0 +1,122
1 using Implab.Parallels;
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6 using System.Threading;
7 using System.Threading.Tasks;
8 using System.Windows.Forms;
9
10 namespace Implab.Diagnostics.Interactive
11 {
12 public class InteractiveListener: TextListenerBase
13 {
14 TraceForm m_form;
15
16 SynchronizationContext m_syncGuiThread;
17 readonly Promise<object> m_guiStarted = new Promise<object>();
18
19 readonly IPromiseBase m_guiFinished;
20 readonly IPromiseBase m_workerFinished = new Promise<object>();
21
22 readonly MTQueue<TraceViewItem> m_queue = new MTQueue<TraceViewItem>();
23 readonly AutoResetEvent m_queueEvent = new AutoResetEvent(false);
24
25 int m_queueLength;
26 bool m_exitPending;
27
28 readonly object m_pauseLock = new object();
29 bool m_paused;
30 readonly ManualResetEvent m_pauseEvent = new ManualResetEvent(true);
31
32 public InteractiveListener(bool global) : base(global) {
33 m_guiFinished = AsyncPool.InvokeNewThread(GuiThread);
34 m_workerFinished = AsyncPool.InvokeNewThread(QueueThread);
35
36 m_guiStarted.Join();
37 }
38
39 void GuiThread() {
40 m_form = new TraceForm(); // will create SynchronizationContext
41
42 m_form.PauseEvents += (s,a) => Pause();
43 m_form.ResumeEvents += (s, a) => Resume();
44
45 m_syncGuiThread = SynchronizationContext.Current;
46 m_guiStarted.Resolve();
47 Application.Run();
48 }
49
50 void QueueThread() {
51 while (!m_exitPending) {
52 if (m_paused)
53 m_pauseEvent.WaitOne();
54
55 TraceViewItem item;
56 if (m_queue.TryDequeue(out item)) {
57 Interlocked.Decrement(ref m_queueLength);
58
59 m_syncGuiThread.Send(x => m_form.AddTraceEvent(item),null);
60 } else {
61 m_queueEvent.WaitOne();
62 }
63 }
64 }
65
66 public void Pause() {
67 // for consistency we need to set this properties atomically
68 lock (m_pauseLock) {
69 m_pauseEvent.Reset();
70 m_paused = true;
71 }
72 }
73
74 public void Resume() {
75 // for consistency we need to set this properties atomically
76 lock (m_pauseLock) {
77 m_paused = false;
78 m_pauseEvent.Set();
79 }
80 }
81
82 void Enqueue(TraceViewItem item) {
83 m_queue.Enqueue(item);
84 if (Interlocked.Increment(ref m_queueLength) == 1)
85 m_queueEvent.Set();
86 }
87
88 public void ShowForm() {
89 m_syncGuiThread.Post(x => m_form.Show(), null);
90 }
91
92 public void HideForm() {
93 m_syncGuiThread.Post(x => m_form.Hide(), null);
94 }
95
96 void Terminate() {
97 m_exitPending = true;
98 Resume();
99 m_syncGuiThread.Post(x => Application.ExitThread(), null);
100 }
101
102 protected override void Dispose(bool disposing) {
103 if (disposing) {
104 Terminate();
105 m_guiFinished.Join();
106 }
107 base.Dispose(disposing);
108 }
109
110 protected override void WriteEntry(TraceContext context, EventText text, string channel) {
111 var item = new TraceViewItem {
112 Indent = text.indent,
113 Message = text.content,
114 Thread = context.ThreadId,
115 Channel = channel,
116 Timestamp = Environment.TickCount
117 };
118
119 Enqueue(item);
120 }
121 }
122 }
@@ -0,0 +1,36
1 using System.Reflection;
2 using System.Runtime.CompilerServices;
3 using System.Runtime.InteropServices;
4
5 // General Information about an assembly is controlled through the following
6 // set of attributes. Change these attribute values to modify the information
7 // associated with an assembly.
8 [assembly: AssemblyTitle("Implab.Diagnostics.Interactive")]
9 [assembly: AssemblyDescription("")]
10 [assembly: AssemblyConfiguration("")]
11 [assembly: AssemblyCompany("")]
12 [assembly: AssemblyProduct("Implab.Diagnostics.Interactive")]
13 [assembly: AssemblyCopyright("Copyright © 2014")]
14 [assembly: AssemblyTrademark("")]
15 [assembly: AssemblyCulture("")]
16
17 // Setting ComVisible to false makes the types in this assembly not visible
18 // to COM components. If you need to access a type in this assembly from
19 // COM, set the ComVisible attribute to true on that type.
20 [assembly: ComVisible(false)]
21
22 // The following GUID is for the ID of the typelib if this project is exposed to COM
23 [assembly: Guid("1c156c51-4884-43b2-a823-d86313872e82")]
24
25 // Version information for an assembly consists of the following four values:
26 //
27 // Major Version
28 // Minor Version
29 // Build Number
30 // Revision
31 //
32 // You can specify all the values or you can default the Build and Revision Numbers
33 // by using the '*' as shown below:
34 // [assembly: AssemblyVersion("1.0.*")]
35 [assembly: AssemblyVersion("1.0.0.0")]
36 [assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,10
1 <?xml version="1.0" encoding="utf-8"?>
2 <!--
3 This file is automatically generated by Visual Studio .Net. It is
4 used to store generic object data source configuration information.
5 Renaming the file extension or editing the content of this file may
6 cause the file to be unrecognizable by the program.
7 -->
8 <GenericObjectDataSource DisplayName="TraceViewItem" Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
9 <TypeInfo>Implab.Diagnostics.Interactive.TraceViewItem, Implab.Diagnostics.Interactive</TypeInfo>
10 </GenericObjectDataSource> No newline at end of file
@@ -0,0 +1,25
1 using System;
2 using System.Collections.Generic;
3 using System.Drawing;
4 using System.Linq;
5 using System.Text;
6 using System.Threading.Tasks;
7
8 namespace Implab.Diagnostics.Interactive {
9 class TextStyle {
10 public Color TextColor {
11 get;
12 set;
13 }
14
15 public FontStyle FontStyle {
16 get;
17 set;
18 }
19
20 public int PaddingLeft {
21 get;
22 set;
23 }
24 }
25 }
@@ -0,0 +1,134
1 namespace Implab.Diagnostics.Interactive {
2 partial class TraceForm {
3 /// <summary>
4 /// Required designer variable.
5 /// </summary>
6 private System.ComponentModel.IContainer components = null;
7
8 /// <summary>
9 /// Clean up any resources being used.
10 /// </summary>
11 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
12 protected override void Dispose(bool disposing) {
13 if (disposing && (components != null)) {
14 components.Dispose();
15 }
16 base.Dispose(disposing);
17 }
18
19 #region Windows Form Designer generated code
20
21 /// <summary>
22 /// Required method for Designer support - do not modify
23 /// the contents of this method with the code editor.
24 /// </summary>
25 private void InitializeComponent() {
26 this.components = new System.ComponentModel.Container();
27 System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
28 System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle();
29 System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle();
30 this.eventsDataGrid = new System.Windows.Forms.DataGridView();
31 this.traceViewItemBindingSource = new System.Windows.Forms.BindingSource(this.components);
32 this.threadDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
33 this.Channel = new System.Windows.Forms.DataGridViewTextBoxColumn();
34 this.messageDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
35 ((System.ComponentModel.ISupportInitialize)(this.eventsDataGrid)).BeginInit();
36 ((System.ComponentModel.ISupportInitialize)(this.traceViewItemBindingSource)).BeginInit();
37 this.SuspendLayout();
38 //
39 // eventsDataGrid
40 //
41 this.eventsDataGrid.AllowUserToAddRows = false;
42 this.eventsDataGrid.AllowUserToDeleteRows = false;
43 this.eventsDataGrid.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
44 | System.Windows.Forms.AnchorStyles.Left)
45 | System.Windows.Forms.AnchorStyles.Right)));
46 this.eventsDataGrid.AutoGenerateColumns = false;
47 this.eventsDataGrid.BackgroundColor = System.Drawing.SystemColors.Window;
48 dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
49 dataGridViewCellStyle1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
50 dataGridViewCellStyle1.Font = new System.Drawing.Font("Lucida Console", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
51 dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.WindowText;
52 dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
53 dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
54 dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
55 this.eventsDataGrid.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
56 this.eventsDataGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
57 this.eventsDataGrid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
58 this.threadDataGridViewTextBoxColumn,
59 this.Channel,
60 this.messageDataGridViewTextBoxColumn});
61 this.eventsDataGrid.DataSource = this.traceViewItemBindingSource;
62 dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
63 dataGridViewCellStyle3.BackColor = System.Drawing.SystemColors.Window;
64 dataGridViewCellStyle3.Font = new System.Drawing.Font("Lucida Console", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
65 dataGridViewCellStyle3.ForeColor = System.Drawing.SystemColors.ControlText;
66 dataGridViewCellStyle3.SelectionBackColor = System.Drawing.SystemColors.Highlight;
67 dataGridViewCellStyle3.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
68 dataGridViewCellStyle3.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
69 this.eventsDataGrid.DefaultCellStyle = dataGridViewCellStyle3;
70 this.eventsDataGrid.Location = new System.Drawing.Point(12, 12);
71 this.eventsDataGrid.Name = "eventsDataGrid";
72 this.eventsDataGrid.ReadOnly = true;
73 this.eventsDataGrid.RowHeadersWidth = 17;
74 this.eventsDataGrid.RowTemplate.Resizable = System.Windows.Forms.DataGridViewTriState.False;
75 this.eventsDataGrid.Size = new System.Drawing.Size(939, 480);
76 this.eventsDataGrid.TabIndex = 1;
77 this.eventsDataGrid.CellFormatting += new System.Windows.Forms.DataGridViewCellFormattingEventHandler(this.eventsDataGrid_CellFormatting);
78 //
79 // traceViewItemBindingSource
80 //
81 this.traceViewItemBindingSource.DataSource = typeof(Implab.Diagnostics.Interactive.TraceViewItem);
82 //
83 // threadDataGridViewTextBoxColumn
84 //
85 this.threadDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
86 this.threadDataGridViewTextBoxColumn.DataPropertyName = "Thread";
87 this.threadDataGridViewTextBoxColumn.HeaderText = "TID";
88 this.threadDataGridViewTextBoxColumn.Name = "threadDataGridViewTextBoxColumn";
89 this.threadDataGridViewTextBoxColumn.ReadOnly = true;
90 this.threadDataGridViewTextBoxColumn.Width = 5;
91 //
92 // Channel
93 //
94 this.Channel.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.DisplayedCells;
95 this.Channel.DataPropertyName = "Channel";
96 this.Channel.HeaderText = "Channel";
97 this.Channel.Name = "Channel";
98 this.Channel.ReadOnly = true;
99 this.Channel.Width = 79;
100 //
101 // messageDataGridViewTextBoxColumn
102 //
103 this.messageDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
104 this.messageDataGridViewTextBoxColumn.DataPropertyName = "FormattedMessage";
105 dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
106 this.messageDataGridViewTextBoxColumn.DefaultCellStyle = dataGridViewCellStyle2;
107 this.messageDataGridViewTextBoxColumn.HeaderText = "Message";
108 this.messageDataGridViewTextBoxColumn.Name = "messageDataGridViewTextBoxColumn";
109 this.messageDataGridViewTextBoxColumn.ReadOnly = true;
110 //
111 // TraceForm
112 //
113 this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
114 this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
115 this.ClientSize = new System.Drawing.Size(963, 504);
116 this.Controls.Add(this.eventsDataGrid);
117 this.Name = "TraceForm";
118 this.Text = "TraceForm";
119 ((System.ComponentModel.ISupportInitialize)(this.eventsDataGrid)).EndInit();
120 ((System.ComponentModel.ISupportInitialize)(this.traceViewItemBindingSource)).EndInit();
121 this.ResumeLayout(false);
122
123 }
124
125 #endregion
126
127 private System.Windows.Forms.DataGridView eventsDataGrid;
128 private System.Windows.Forms.BindingSource traceViewItemBindingSource;
129 private System.Windows.Forms.DataGridViewTextBoxColumn threadDataGridViewTextBoxColumn;
130 private System.Windows.Forms.DataGridViewTextBoxColumn Channel;
131 private System.Windows.Forms.DataGridViewTextBoxColumn messageDataGridViewTextBoxColumn;
132
133 }
134 } No newline at end of file
@@ -0,0 +1,53
1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.Linq;
7 using System.Text;
8 using System.Threading.Tasks;
9 using System.Windows.Forms;
10
11 namespace Implab.Diagnostics.Interactive {
12 public partial class TraceForm : Form {
13 readonly Dictionary<int, Color> m_threadColors = new Dictionary<int,Color>();
14 readonly Random m_rand = new Random();
15
16 public event EventHandler PauseEvents;
17
18 public event EventHandler ResumeEvents;
19
20 public TraceForm() {
21 InitializeComponent();
22 }
23
24 protected override void OnFormClosing(FormClosingEventArgs e) {
25 base.OnFormClosing(e);
26 if (!e.Cancel && e.CloseReason == CloseReason.UserClosing) {
27 e.Cancel = true;
28 Hide();
29 }
30 }
31
32 public void AddTraceEvent(TraceViewItem item) {
33 traceViewItemBindingSource.Add(item);
34 eventsDataGrid.FirstDisplayedScrollingRowIndex = eventsDataGrid.RowCount - 1;
35 }
36
37 Color GetThreadColor(int thread) {
38 Color result;
39 if (!m_threadColors.TryGetValue(thread, out result)) {
40 result = Color.FromArgb(m_rand.Next(4)*64, m_rand.Next(4)*64, m_rand.Next(4)*64);
41 m_threadColors[thread] = result;
42 }
43 return result;
44 }
45
46 private void eventsDataGrid_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) {
47 var data = (TraceViewItem)traceViewItemBindingSource[e.RowIndex];
48 if (e.ColumnIndex == messageDataGridViewTextBoxColumn.Index)
49 e.CellStyle.Padding = new Padding(data.Indent * 10,0,0,0);
50 e.CellStyle.ForeColor = GetThreadColor(data.Thread);
51 }
52 }
53 }
@@ -0,0 +1,126
1 <?xml version="1.0" encoding="utf-8"?>
2 <root>
3 <!--
4 Microsoft ResX Schema
5
6 Version 2.0
7
8 The primary goals of this format is to allow a simple XML format
9 that is mostly human readable. The generation and parsing of the
10 various data types are done through the TypeConverter classes
11 associated with the data types.
12
13 Example:
14
15 ... ado.net/XML headers & schema ...
16 <resheader name="resmimetype">text/microsoft-resx</resheader>
17 <resheader name="version">2.0</resheader>
18 <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
19 <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
20 <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
21 <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
22 <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
23 <value>[base64 mime encoded serialized .NET Framework object]</value>
24 </data>
25 <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
26 <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
27 <comment>This is a comment</comment>
28 </data>
29
30 There are any number of "resheader" rows that contain simple
31 name/value pairs.
32
33 Each data row contains a name, and value. The row also contains a
34 type or mimetype. Type corresponds to a .NET class that support
35 text/value conversion through the TypeConverter architecture.
36 Classes that don't support this are serialized and stored with the
37 mimetype set.
38
39 The mimetype is used for serialized objects, and tells the
40 ResXResourceReader how to depersist the object. This is currently not
41 extensible. For a given mimetype the value must be set accordingly:
42
43 Note - application/x-microsoft.net.object.binary.base64 is the format
44 that the ResXResourceWriter will generate, however the reader can
45 read any of the formats listed below.
46
47 mimetype: application/x-microsoft.net.object.binary.base64
48 value : The object must be serialized with
49 : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
50 : and then encoded with base64 encoding.
51
52 mimetype: application/x-microsoft.net.object.soap.base64
53 value : The object must be serialized with
54 : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
55 : and then encoded with base64 encoding.
56
57 mimetype: application/x-microsoft.net.object.bytearray.base64
58 value : The object must be serialized into a byte array
59 : using a System.ComponentModel.TypeConverter
60 : and then encoded with base64 encoding.
61 -->
62 <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
63 <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
64 <xsd:element name="root" msdata:IsDataSet="true">
65 <xsd:complexType>
66 <xsd:choice maxOccurs="unbounded">
67 <xsd:element name="metadata">
68 <xsd:complexType>
69 <xsd:sequence>
70 <xsd:element name="value" type="xsd:string" minOccurs="0" />
71 </xsd:sequence>
72 <xsd:attribute name="name" use="required" type="xsd:string" />
73 <xsd:attribute name="type" type="xsd:string" />
74 <xsd:attribute name="mimetype" type="xsd:string" />
75 <xsd:attribute ref="xml:space" />
76 </xsd:complexType>
77 </xsd:element>
78 <xsd:element name="assembly">
79 <xsd:complexType>
80 <xsd:attribute name="alias" type="xsd:string" />
81 <xsd:attribute name="name" type="xsd:string" />
82 </xsd:complexType>
83 </xsd:element>
84 <xsd:element name="data">
85 <xsd:complexType>
86 <xsd:sequence>
87 <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
88 <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
89 </xsd:sequence>
90 <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
91 <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
92 <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
93 <xsd:attribute ref="xml:space" />
94 </xsd:complexType>
95 </xsd:element>
96 <xsd:element name="resheader">
97 <xsd:complexType>
98 <xsd:sequence>
99 <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
100 </xsd:sequence>
101 <xsd:attribute name="name" type="xsd:string" use="required" />
102 </xsd:complexType>
103 </xsd:element>
104 </xsd:choice>
105 </xsd:complexType>
106 </xsd:element>
107 </xsd:schema>
108 <resheader name="resmimetype">
109 <value>text/microsoft-resx</value>
110 </resheader>
111 <resheader name="version">
112 <value>2.0</value>
113 </resheader>
114 <resheader name="reader">
115 <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
116 </resheader>
117 <resheader name="writer">
118 <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
119 </resheader>
120 <metadata name="Channel.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
121 <value>True</value>
122 </metadata>
123 <metadata name="traceViewItemBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
124 <value>17, 17</value>
125 </metadata>
126 </root> No newline at end of file
@@ -0,0 +1,26
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.Diagnostics.Interactive {
8 public class TraceViewItem {
9 string m_formattedValue;
10
11 public string Message { get; set; }
12 public int Timestamp { get; set; }
13 public int Indent { get; set; }
14 public int Thread { get; set; }
15 public string Channel { get; set; }
16
17 public string FormattedMessage {
18 get {
19 if (m_formattedValue == null) {
20 m_formattedValue = Message.Replace("\r",String.Empty).Replace("\n", " | ");
21 }
22 return m_formattedValue;
23 }
24 }
25 }
26 }
@@ -1,13 +1,15
1 syntax: glob
1 syntax: glob
2 Implab.Test/bin/
2 Implab.Test/bin/
3 *.user
3 *.user
4 Implab.Test/obj/
4 Implab.Test/obj/
5 *.userprefs
5 *.userprefs
6 Implab/bin/
6 Implab/bin/
7 Implab/obj/
7 Implab/obj/
8 TestResults/
8 TestResults/
9 Implab.Fx/obj/
9 Implab.Fx/obj/
10 Implab.Fx/bin/
10 Implab.Fx/bin/
11 Implab.Fx.Test/bin/
11 Implab.Fx.Test/bin/
12 Implab.Fx.Test/obj/
12 Implab.Fx.Test/obj/
13 _ReSharper.Implab/
13 _ReSharper.Implab/
14 Implab.Diagnostics.Interactive/bin/
15 Implab.Diagnostics.Interactive/obj/
@@ -1,34 +1,34
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.Linq;
3 using System.Linq;
4 using System.Text;
4 using System.Text;
5
5
6 namespace Implab.Diagnostics {
6 namespace Implab.Diagnostics {
7 public class ConsoleTraceListener: TextListenerBase {
7 public class ConsoleTraceListener: TextListenerBase {
8
8
9 static readonly object _consoleLock = new object();
9 static readonly object _consoleLock = new object();
10
10
11 public ConsoleTraceListener()
11 public ConsoleTraceListener()
12 : base(true) {
12 : base(true) {
13
13
14 }
14 }
15
15
16 public ConsoleTraceListener(bool local)
16 public ConsoleTraceListener(bool global)
17 : base(local) {
17 : base(global) {
18
18
19 }
19 }
20
20
21 protected override void WriteEntry(TraceContext context, EventText text) {
21 protected override void WriteEntry(TraceContext context, EventText text, string channel) {
22 var msg = new StringBuilder();
22 var msg = new StringBuilder();
23
23
24 for (int i = 0; i < text.indent; i++)
24 for (int i = 0; i < text.indent; i++)
25 msg.Append(" ");
25 msg.Append(" ");
26 msg.AppendFormat("[{0}]: {1}", context.ThreadId, text.content);
26 msg.AppendFormat("[{0}]:{1}: {2}", context.ThreadId, channel, text.content);
27
27
28 lock (_consoleLock) {
28 lock (_consoleLock) {
29 Console.ForegroundColor = (ConsoleColor)(context.ThreadId % 15 + 1);
29 Console.ForegroundColor = (ConsoleColor)(context.ThreadId % 15 + 1);
30 Console.WriteLine(msg.ToString());
30 Console.WriteLine(msg.ToString());
31 }
31 }
32 }
32 }
33 }
33 }
34 }
34 }
@@ -1,30 +1,81
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.Linq;
3 using System.Linq;
4 using System.Text;
4 using System.Text;
5
5
6 namespace Implab.Diagnostics {
6 namespace Implab.Diagnostics {
7 /// <summary>
8 /// Канал, через который публикуются события журнала.
9 /// </summary>
10 /// <typeparam name="TEvent">Тип событий в канале</typeparam>
11 /// <remarks>
12 /// Событиями журнала могут быть любые типы, например строки, в которых будет передаваться
13 /// информация, или структуры с набором полей, описывающих важность, текст и другую информацию.
14 /// </remarks>
7 public class LogChannel<TEvent> {
15 public class LogChannel<TEvent> {
8 static LogChannel<TEvent> _default = new LogChannel<TEvent>();
16 static LogChannel<TEvent> _default = new LogChannel<TEvent>();
9
17
18 /// <summary>
19 /// Канал по-умолчанию для событий типа <typeparam name="TEvent"/>.
20 /// </summary>
10 public static LogChannel<TEvent> Default {
21 public static LogChannel<TEvent> Default {
11 get {
22 get {
12 return _default;
23 return _default;
13 }
24 }
14 }
25 }
15
26
27 /// <summary>
28 /// Событие появление новой записи в журнале, на это событие подписываются слушатели.
29 /// </summary>
16 public event EventHandler<ValueEventArgs<TEvent>> Events;
30 public event EventHandler<ValueEventArgs<TEvent>> Events;
17
31
32 /// <summary>
33 /// Имя канала, полезно для отображения в журнале
34 /// </summary>
35 public string Name {
36 get;
37 private set;
38 }
39
40 /// <summary>
41 /// Создает журнал, имя типа событий назначается в качетве имени канала.
42 /// </summary>
43 public LogChannel()
44 : this(null) {
45 }
46
47 /// <summary>
48 /// Содает канал с указанным именем.
49 /// </summary>
50 /// <param name="name">Имя канала.</param>
51 public LogChannel(string name) {
52 if (String.IsNullOrEmpty(name))
53 name = typeof(TEvent).Name;
54 Name = name;
55 }
56
57 /// <summary>
58 /// Отправляет запись журнала через канал подписчикам.
59 /// </summary>
60 /// <param name="data">Запись журнала.</param>
61 /// <remarks>
62 /// Контекст трассировки от которого рассылается сообщение определяется автоматически из текущего потока.
63 /// </remarks>
18 public void LogEvent(TEvent data) {
64 public void LogEvent(TEvent data) {
19 var t = Events;
65 var t = Events;
20 if (t!= null)
66 if (t!= null)
21 t(TraceContext.Current,new ValueEventArgs<TEvent>(data));
67 t(TraceContext.Current,new ValueEventArgs<TEvent>(data));
22 }
68 }
23
69
70 /// <summary>
71 /// Отправляет запись журнала через канал подписчикам.
72 /// </summary>
73 /// <param name="data">Запись журнала.</param>
74 /// <param name="context">Контекст трассировки от которого рассылается сообщение/</param>
24 public void LogEvent(TraceContext context,TEvent data) {
75 public void LogEvent(TraceContext context,TEvent data) {
25 var t = Events;
76 var t = Events;
26 if (t != null)
77 if (t != null)
27 t(context, new ValueEventArgs<TEvent>(data));
78 t(context, new ValueEventArgs<TEvent>(data));
28 }
79 }
29 }
80 }
30 }
81 }
@@ -1,44 +1,47
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.IO;
3 using System.IO;
4 using System.Linq;
4 using System.Linq;
5 using System.Text;
5 using System.Text;
6
6
7 namespace Implab.Diagnostics {
7 namespace Implab.Diagnostics {
8 public class TextFileListener: TextListenerBase {
8 public class TextFileListener: TextListenerBase {
9 readonly TextWriter m_textWriter;
9 readonly TextWriter m_textWriter;
10
10
11 public TextFileListener(string fileName, bool local) : base(local) {
11 public TextFileListener(string fileName, bool global)
12 : base(global) {
12 m_textWriter = File.CreateText(fileName);
13 m_textWriter = File.CreateText(fileName);
13
14
14 m_textWriter.WriteLine("LOG {0}", DateTime.Now);
15 m_textWriter.WriteLine("LOG {0}", DateTime.Now);
15 Register(this);
16 Register(this);
16 }
17 }
17
18
18 protected override void WriteEntry(TraceContext context, EventText text) {
19 protected override void WriteEntry(TraceContext context, EventText text, string channel) {
19 var msg = new StringBuilder();
20 var msg = new StringBuilder();
20 for (int i = 0; i < text.indent; i++)
21 for (int i = 0; i < text.indent; i++)
21 msg.Append(" ");
22 msg.Append(" ");
22 msg.AppendFormat("[{0}]: {1}", context.ThreadId, text.content);
23 msg.AppendFormat("[{0}]:{1}: {2}", context.ThreadId, channel, text.content);
23
24
24 lock (m_textWriter) {
25 lock (m_textWriter) {
25 if (!IsDisposed) {
26 if (!IsDisposed) {
27 // тут гарантировано еще не освобожден m_textWriter
26 m_textWriter.WriteLine(msg.ToString());
28 m_textWriter.WriteLine(msg.ToString());
27 m_textWriter.Flush();
29 m_textWriter.Flush();
28 }
30 }
29 }
31 }
30 }
32 }
31
33
32
34
33 protected override void Dispose(bool disposing) {
35 protected override void Dispose(bool disposing) {
34 base.Dispose(disposing);
36 base.Dispose(disposing);
35 if (disposing) {
37 if (disposing) {
38 // IsDisposed = true
36 lock (m_textWriter) {
39 lock (m_textWriter) {
37 Safe.Dispose(m_textWriter);
40 Safe.Dispose(m_textWriter);
38 }
41 }
39 }
42 }
40 }
43 }
41
44
42
45
43 }
46 }
44 }
47 }
@@ -1,119 +1,129
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.Linq;
3 using System.Linq;
4 using System.Text;
4 using System.Text;
5
5
6 namespace Implab.Diagnostics {
6 namespace Implab.Diagnostics {
7 public abstract class TextListenerBase : ServiceLocator, IEventTextFormatter<object>, IEventTextFormatter<TraceEvent> {
7 public abstract class TextListenerBase : ServiceLocator, IEventTextFormatter<object>, IEventTextFormatter<TraceEvent> {
8
8
9 readonly Dictionary<object, Action> m_subscriptions = new Dictionary<object, Action>();
9 readonly Dictionary<object, Action> m_subscriptions = new Dictionary<object, Action>();
10 readonly LogicalOperation m_boundOperation;
10 readonly LogicalOperation m_boundOperation;
11 readonly int m_baseIndent;
11 readonly int m_baseIndent;
12
12
13 protected TextListenerBase(bool local) {
13 protected TextListenerBase(bool global) {
14 Register(this);
14 Register(this);
15 if (local) {
15 if (!global) {
16 m_boundOperation = TraceContext.Current.CurrentOperation;
16 m_boundOperation = TraceContext.Current.CurrentOperation;
17 m_baseIndent = Math.Max(0, m_boundOperation.Level - 1);
17 m_baseIndent = Math.Max(0, m_boundOperation.Level - 1);
18 }
18 }
19 }
19 }
20
20
21 public void Subscribe(Type eventType) {
21 public void Subscribe(Type eventType) {
22 if (eventType == null)
22 if (eventType == null)
23 throw new ArgumentNullException("eventType");
23 throw new ArgumentNullException("eventType");
24 GetType().GetMethod("Subscribe", new Type[0]).MakeGenericMethod(eventType).Invoke(this, null);
24 GetType().GetMethod("Subscribe", new Type[0]).MakeGenericMethod(eventType).Invoke(this, null);
25 }
25 }
26
26
27 public void Subscribe<TEvent>() {
27 public void Subscribe<TEvent>() {
28 Subscribe<TEvent>(LogChannel<TEvent>.Default);
28 Subscribe<TEvent>(LogChannel<TEvent>.Default);
29 }
29 }
30
30
31 public void Subscribe<TEvent>(LogChannel<TEvent> channel) {
31 public void Subscribe<TEvent>(LogChannel<TEvent> channel) {
32 if (channel == null)
32 if (channel == null)
33 throw new ArgumentNullException("channel");
33 throw new ArgumentNullException("channel");
34
34
35 lock (m_subscriptions) {
35 lock (m_subscriptions) {
36 AssertNotDisposed();
36 AssertNotDisposed();
37
37
38 var formatter = GetService<IEventTextFormatter<TEvent>>();
38 var formatter = GetService<IEventTextFormatter<TEvent>>();
39 var channelName = channel.Name;
39
40
40 EventHandler<ValueEventArgs<TEvent>> handler = (sender, args) => {
41 EventHandler<ValueEventArgs<TEvent>> handler = (sender, args) => {
41 TraceContext context = (TraceContext)sender;
42 TraceContext context = (TraceContext)sender;
42 var text = formatter.Format(context, args.Value);
43 var text = formatter.Format(context, args.Value);
43 text.indent -= m_baseIndent;
44 text.indent -= m_baseIndent;
44
45
45 if (IsRelated(context.CurrentOperation))
46 if (IsRelated(context.CurrentOperation))
46 WriteEntry(context, text);
47 WriteEntry(context, text, channelName);
47 };
48 };
48
49
49 if (m_subscriptions.ContainsKey(channel))
50 if (m_subscriptions.ContainsKey(channel))
50 return;
51 return;
51
52
52 channel.Events += handler;
53 channel.Events += handler;
53
54
54 Action unsubscribe = () => {
55 Action unsubscribe = () => {
55 channel.Events -= handler;
56 channel.Events -= handler;
56 };
57 };
57
58
58 m_subscriptions.Add(channel, unsubscribe);
59 m_subscriptions.Add(channel, unsubscribe);
59 }
60 }
60 }
61 }
61
62
62 public bool IsRelated(LogicalOperation op) {
63 public bool IsRelated(LogicalOperation op) {
63 if (m_boundOperation == null)
64 if (m_boundOperation == null)
64 return true;
65 return true;
65
66
66 while (op != m_boundOperation && op.Level > m_boundOperation.Level)
67 while (op != m_boundOperation && op.Level > m_boundOperation.Level)
67 op = op.Parent;
68 op = op.Parent;
68 return op == m_boundOperation;
69 return op == m_boundOperation;
69 }
70 }
70
71
71 public void Unsubscribe<TEvent>(LogChannel<TEvent> channel) {
72 public void Unsubscribe<TEvent>(LogChannel<TEvent> channel) {
72 if (channel == null)
73 if (channel == null)
73 throw new ArgumentNullException("channel");
74 throw new ArgumentNullException("channel");
74
75
75 lock (m_subscriptions) {
76 lock (m_subscriptions) {
76 Action subscription;
77 Action subscription;
77 if (m_subscriptions.TryGetValue(channel, out subscription)) {
78 if (m_subscriptions.TryGetValue(channel, out subscription)) {
78 subscription();
79 subscription();
79 m_subscriptions.Remove(channel);
80 m_subscriptions.Remove(channel);
80 }
81 }
81 }
82 }
82 }
83 }
83
84
84 public void UnsubscribeAll() {
85 public void UnsubscribeAll() {
85 lock (m_subscriptions) {
86 lock (m_subscriptions) {
86 foreach (var subscription in m_subscriptions.Values)
87 foreach (var subscription in m_subscriptions.Values)
87 subscription();
88 subscription();
88 m_subscriptions.Clear();
89 m_subscriptions.Clear();
89 }
90 }
90 }
91 }
91
92
92 protected abstract void WriteEntry(TraceContext context, EventText text);
93 /// <summary>
94 /// Вызывается для записи текста сообщения, в журнал.
95 /// </summary>
96 /// <remarks>
97 /// Данный метод может вызваться из разных потоков одновременно. Возможна ситуация, когда
98 /// данный метод вызывается уже после освобождения ообъекта методом <see cref="Dispose()"/>.
99 /// </remarks>
100 /// <param name="context">Контекст трассировки.</param>
101 /// <param name="text">Текст сообщения.</param>
102 protected abstract void WriteEntry(TraceContext context, EventText text, string channel);
93
103
94 public EventText Format(TraceContext context, object data) {
104 public EventText Format(TraceContext context, object data) {
95 return new EventText {
105 return new EventText {
96 indent = context.CurrentOperation.Level,
106 indent = context.CurrentOperation.Level,
97 content = data.ToString()
107 content = data.ToString()
98 };
108 };
99 }
109 }
100
110
101 public EventText Format(TraceContext context, TraceEvent data) {
111 public EventText Format(TraceContext context, TraceEvent data) {
102 var level = context.CurrentOperation.Level;
112 var level = context.CurrentOperation.Level;
103 if (data.EventType == TraceEventType.OperationCompleted || data.EventType == TraceEventType.OperationStarted)
113 if (data.EventType == TraceEventType.OperationCompleted || data.EventType == TraceEventType.OperationStarted)
104 level--;
114 level--;
105
115
106 return new EventText {
116 return new EventText {
107 indent = level,
117 indent = level,
108 content = data.ToString()
118 content = data.ToString()
109 };
119 };
110 }
120 }
111
121
112 protected override void Dispose(bool disposing) {
122 protected override void Dispose(bool disposing) {
123 base.Dispose(disposing);
113 if (disposing) {
124 if (disposing) {
114 UnsubscribeAll();
125 UnsubscribeAll();
115 }
126 }
116 base.Dispose(disposing);
117 }
127 }
118 }
128 }
119 }
129 }
@@ -1,172 +1,211
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.Linq;
3 using System.Linq;
4 using System.Text;
4 using System.Text;
5 using System.Threading;
5 using System.Threading;
6 using System.Threading.Tasks;
6 using System.Threading.Tasks;
7
7
8 namespace Implab.Diagnostics {
8 namespace Implab.Diagnostics {
9 /// <summary>
9 /// <summary>
10 /// Контекст трассировки, привязывается к потоку и содержит в себе информацию о стеке логических операций.
10 /// Контекст трассировки, привязывается к потоку и содержит в себе информацию о стеке логических операций.
11 /// </summary>
11 /// </summary>
12 /// <remarks>
12 /// <remarks>
13 /// Контекст трассировки передается слушателям событий для определения места, где возникло событие.
13 /// Контекст трассировки передается слушателям событий для определения места, где возникло событие.
14 /// </remarks>
14 /// </remarks>
15 public class TraceContext {
15 public class TraceContext {
16 LogicalOperation m_currentOperation;
16 LogicalOperation m_currentOperation;
17 readonly LogicalOperation m_bound;
17 readonly LogicalOperation m_bound;
18 readonly int m_threadId;
18 readonly int m_threadId;
19
19
20 [ThreadStatic]
20 [ThreadStatic]
21 static TraceContext _current;
21 static TraceContext _current;
22
22
23 /// <summary>
23 /// <summary>
24 /// Текущий контекст трассировки для потока, создается астоматически при первом обращении.
24 /// Текущий контекст трассировки для потока, создается астоматически при первом обращении.
25 /// </summary>
25 /// </summary>
26 public static TraceContext Current {
26 public static TraceContext Current {
27 get {
27 get {
28 if (_current == null)
28 if (_current == null) {
29 _current = new TraceContext();
29 _current = new TraceContext();
30 _current.LogEvent(TraceEventType.Created,"[{0}]", _current.ThreadId);
31 }
30 return _current;
32 return _current;
31 }
33 }
32 }
34 }
33
35
34 TraceContext(TraceContext context) {
36 TraceContext(TraceContext context)
37 : this(context, false) {
38 }
39
40 TraceContext(TraceContext context, bool attach) {
35 if (context == null)
41 if (context == null)
36 throw new ArgumentNullException("context");
42 throw new ArgumentNullException("context");
37
43
38 m_currentOperation = context.CurrentOperation;
44 m_currentOperation = context.CurrentOperation;
39 m_bound = context.CurrentOperation;
45 m_bound = attach ? context.BoundOperation : context.CurrentOperation;
40 m_threadId = Thread.CurrentThread.ManagedThreadId;
46 m_threadId = Thread.CurrentThread.ManagedThreadId;
41 }
47 }
42
48
43 TraceContext() {
49 TraceContext() {
44 m_currentOperation = new LogicalOperation();
50 m_currentOperation = new LogicalOperation();
45 m_bound = m_currentOperation;
51 m_bound = m_currentOperation;
46 m_threadId = Thread.CurrentThread.ManagedThreadId;
52 m_threadId = Thread.CurrentThread.ManagedThreadId;
47 }
53 }
48
54
49 /// <summary>
55 /// <summary>
50 /// При необходимости копирует состояние контекста трассивровки в текущий поток.
56 /// При необходимости копирует состояние контекста трассивровки в текущий поток.
51 /// </summary>
57 /// </summary>
52 /// <param name="from">Исходный контекст трассировки, который передается.</param>
58 /// <param name="from">Исходный контекст трассировки, который передается.</param>
53 /// <remarks>
59 /// <remarks>
54 /// <para>
60 /// <para>
55 /// Копирование происходит за счет создания нового контекста трассировки и заполнением его
61 /// Копирование происходит за счет создания нового контекста трассировки и заполнением его
56 /// состояния из переданного контекста. При этом копируется стек операций, однако в новом
62 /// состояния из переданного контекста. При этом копируется стек операций, однако в новом
57 /// контексте ранее начатые логические операции не могут быть завершены.
63 /// контексте ранее начатые логические операции не могут быть завершены.
58 /// </para>
64 /// </para>
59 /// <para>
65 /// <para>
60 /// Если передача состояния состоялась, то вызывается событие трассировки <see cref="TraceEventType.Transfer"/>.
66 /// Если передача состояния состоялась, то вызывается событие трассировки <see cref="TraceEventType.Fork"/>.
61 /// </para>
67 /// </para>
62 /// </remarks>
68 /// </remarks>
63 public static void Transfer(TraceContext from) {
69 public static void Fork(TraceContext from) {
64 if (_current == from)
70 if (_current == from)
65 return;
71 return;
66 if (from != null) {
72 if (from != null) {
67 var context = new TraceContext(from);
73 var context = new TraceContext(from);
68 context.LogEvent(TraceEventType.Transfer, "[{0}]-->[{1}]",from.ThreadId, context.ThreadId);
74 context.LogEvent(TraceEventType.Fork, "[{0}]-->[{1}]",from.ThreadId, context.ThreadId);
69 _current = context;
75 _current = context;
70 } else {
76 } else {
71 _current = new TraceContext();
77 _current = new TraceContext();
72 }
78 }
73 }
79 }
74
80
75 /// <summary>
81 /// <summary>
76 /// Создает постоянную копию текущего контекста, данную копию можно хранить и использовать для передачи через <see cref="Transfer(TraceContext)"/>
82 /// Задает текущему потоку указанный контекст, текущей поток может заканчивать ранее начатые
83 /// логические операции в указанном контексте.
84 /// </summary>
85 /// <param name="source"></param>
86 public static void Attach(TraceContext source) {
87 if (_current == source)
88 return;
89 if (source != null) {
90 var context = new TraceContext(source, true);
91 context.LogEvent(TraceEventType.Attach, "[{0}]-->[{1}]", source.ThreadId, context.ThreadId);
92 _current = context;
93 } else {
94 _current = new TraceContext();
95 }
96 }
97
98 /// <summary>
99 /// Отсоединяет текущий контекст трассировки от потока, для дальнейшей его передачи другому потоку
100 /// <see cref="Attach(TraceContext)"/>.
101 /// </summary>
102 /// <returns>Контекст трассировки потока</returns>
103 /// <remarks>
104 /// После отсоединения контекста трассировки от потока, при первом обращении к трассировке в этом
105 /// потоке будет создан новый контекст.
106 /// </remarks>
107 public static TraceContext Detach() {
108 var context = Current;
109 context.LogEvent(TraceEventType.Detach, null);
110 _current = null;
111 return context;
112 }
113
114 /// <summary>
115 /// Создает постоянную копию текущего контекста, данную копию можно хранить и использовать для передачи через <see cref="Fork(TraceContext)"/>
77 /// </summary>
116 /// </summary>
78 /// <returns>Копия текущего контекста трассировки.</returns>
117 /// <returns>Копия текущего контекста трассировки.</returns>
79 public static TraceContext Snapshot() {
118 public static TraceContext Snapshot() {
80 return _current == null ? new TraceContext() : new TraceContext(_current);
119 return _current == null ? new TraceContext() : new TraceContext(_current);
81 }
120 }
82
121
83 /// <summary>
122 /// <summary>
84 /// Выполняет переданное действие в указанном контексте трассировки, по окончании восстанавливает предыдущий контекст трассировки потока.
123 /// Выполняет переданное действие в указанном контексте трассировки, по окончании восстанавливает предыдущий контекст трассировки потока.
85 /// </summary>
124 /// </summary>
86 /// <param name="action"></param>
125 /// <param name="action"></param>
87 public void Invoke(Action action) {
126 public void Invoke(Action action) {
88 if (action == null)
127 if (action == null)
89 throw new ArgumentNullException("action");
128 throw new ArgumentNullException("action");
90 var old = _current;
129 var old = _current;
91 Transfer(this);
130 Fork(this);
92 try {
131 try {
93 action();
132 action();
94 } finally {
133 } finally {
95 _current.EndAllOperations();
134 _current.EndAllOperations();
96 _current = old;
135 _current = old;
97 }
136 }
98 }
137 }
99
138
100 /// <summary>
139 /// <summary>
101 /// Текущая логическая операция.
140 /// Текущая логическая операция.
102 /// </summary>
141 /// </summary>
103 public LogicalOperation CurrentOperation {
142 public LogicalOperation CurrentOperation {
104 get {
143 get {
105 return m_currentOperation;
144 return m_currentOperation;
106 }
145 }
107 }
146 }
108
147
109 /// <summary>
148 /// <summary>
110 /// Операция ниже которой нельзя опускаться в стеке логических операций, т.е. она не может быть завершена в текущем контексте.
149 /// Операция ниже которой нельзя опускаться в стеке логических операций, т.е. она не может быть завершена в текущем контексте.
111 /// </summary>
150 /// </summary>
112 public LogicalOperation BoundOperation {
151 public LogicalOperation BoundOperation {
113 get {
152 get {
114 return m_bound;
153 return m_bound;
115 }
154 }
116 }
155 }
117
156
118 /// <summary>
157 /// <summary>
119 /// Поток, в котором создан контекст трассировки.
158 /// Поток, в котором создан контекст трассировки.
120 /// </summary>
159 /// </summary>
121 public int ThreadId {
160 public int ThreadId {
122 get {
161 get {
123 return m_threadId;
162 return m_threadId;
124 }
163 }
125 }
164 }
126
165
127 /// <summary>
166 /// <summary>
128 /// Начинает безымянную логическую операцию.
167 /// Начинает безымянную логическую операцию.
129 /// </summary>
168 /// </summary>
130 public void StartLogicalOperation() {
169 public void StartLogicalOperation() {
131 StartLogicalOperation(null);
170 StartLogicalOperation(null);
132 }
171 }
133
172
134 /// <summary>
173 /// <summary>
135 /// Начинает логическую операцию с указанным именем. Созданная операция будет добвалена в стек логических операций контекста, затем будет создано соответсвующее событие.
174 /// Начинает логическую операцию с указанным именем. Созданная операция будет добвалена в стек логических операций контекста, затем будет создано соответсвующее событие.
136 /// </summary>
175 /// </summary>
137 /// <param name="name">Имя начинаемой операции.</param>
176 /// <param name="name">Имя начинаемой операции.</param>
138 public void StartLogicalOperation(string name) {
177 public void StartLogicalOperation(string name) {
139 m_currentOperation = new LogicalOperation(name, m_currentOperation);
178 m_currentOperation = new LogicalOperation(name, m_currentOperation);
140 LogEvent(TraceEventType.OperationStarted, name);
179 LogEvent(TraceEventType.OperationStarted, name);
141 }
180 }
142
181
143 /// <summary>
182 /// <summary>
144 /// Заканчивает логическую операцию начатую в текущем контексте. Операции, начатые в других контекстах не могут быть закончены в текущем контексте.
183 /// Заканчивает логическую операцию начатую в текущем контексте. Операции, начатые в других контекстах не могут быть закончены в текущем контексте.
145 /// </summary>
184 /// </summary>
146 /// <remarks>
185 /// <remarks>
147 /// При вызове данного метода создается событие журнала трассировки, либо о завершении операции, либо об ошибки, поскольку данная операция
186 /// При вызове данного метода создается событие журнала трассировки, либо о завершении операции, либо об ошибки, поскольку данная операция
148 /// начата в другом контексте.
187 /// начата в другом контексте.
149 /// </remarks>
188 /// </remarks>
150 public void EndLogicalOperation() {
189 public void EndLogicalOperation() {
151 if (m_bound == m_currentOperation) {
190 if (m_bound == m_currentOperation) {
152 LogEvent(TraceEventType.Error, "Trying to end the operation which isn't belongs to current trace");
191 LogEvent(TraceEventType.Error, "Trying to end the operation which isn't belongs to current trace");
153 } else {
192 } else {
154 var op = m_currentOperation;
193 var op = m_currentOperation;
155 LogEvent(TraceEventType.OperationCompleted, "{0} {1} ms", op.Name, op.Duration);
194 LogEvent(TraceEventType.OperationCompleted, "{0} {1} ms", op.Name, op.Duration);
156 m_currentOperation = m_currentOperation.Parent;
195 m_currentOperation = m_currentOperation.Parent;
157 }
196 }
158 }
197 }
159
198
160 /// <summary>
199 /// <summary>
161 /// Заврешает все начатые в этом контексте операции
200 /// Заврешает все начатые в этом контексте операции
162 /// </summary>
201 /// </summary>
163 public void EndAllOperations() {
202 public void EndAllOperations() {
164 while (m_bound != m_currentOperation)
203 while (m_bound != m_currentOperation)
165 EndLogicalOperation();
204 EndLogicalOperation();
166 }
205 }
167
206
168 void LogEvent(TraceEventType type, string format, params object[] args) {
207 void LogEvent(TraceEventType type, string format, params object[] args) {
169 LogChannel<TraceEvent>.Default.LogEvent(this, TraceEvent.Create(type, format, args));
208 LogChannel<TraceEvent>.Default.LogEvent(this, TraceEvent.Create(type, format, args));
170 }
209 }
171 }
210 }
172 }
211 }
@@ -1,16 +1,19
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.Linq;
3 using System.Linq;
4 using System.Text;
4 using System.Text;
5 using System.Threading.Tasks;
5 using System.Threading.Tasks;
6
6
7 namespace Implab.Diagnostics {
7 namespace Implab.Diagnostics {
8 public enum TraceEventType {
8 public enum TraceEventType {
9 Information = 1,
9 Information = 1,
10 Warning,
10 Warning,
11 Error,
11 Error,
12 OperationStarted,
12 OperationStarted,
13 OperationCompleted,
13 OperationCompleted,
14 Transfer
14 Fork,
15 Attach,
16 Detach,
17 Created
15 }
18 }
16 }
19 }
@@ -1,46 +1,62
1 using System;
1 using Implab.Diagnostics;
2 using System;
2 using System.Collections.Generic;
3 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Diagnostics;
4 using System.Linq;
5 using System.Linq;
5 using System.Web;
6 using System.Web;
6
7
7 namespace Implab {
8 namespace Implab {
9 /// <summary>
10 /// Объект, поддерживающий освобождение ресурсов.
11 /// </summary>
8 public class Disposable : IDisposable {
12 public class Disposable : IDisposable {
9
13
10 bool m_disposed;
14 bool m_disposed;
11
15
12 public event EventHandler Disposed;
16 public event EventHandler Disposed;
13
17
14 public bool IsDisposed {
18 public bool IsDisposed {
15 get { return m_disposed; }
19 get { return m_disposed; }
16 }
20 }
17
21
18 protected void AssertNotDisposed() {
22 protected void AssertNotDisposed() {
19 if (m_disposed)
23 if (m_disposed)
20 throw new ObjectDisposedException(this.ToString());
24 throw new ObjectDisposedException(this.ToString());
21 }
25 }
22
26 /// <summary>
27 /// Переводит объект в состояние <c>Disposed</c> и вызывает событие <see cref="Disposed"/>
28 /// </summary>
29 /// <param name="disposing">Признак того, что нужно освободить ресурсы, иначе данный метод
30 /// вызван сборщиком мусора и нужно освобождать ТОЛЬКО неуправляемые ресурсы ТОЛЬКО этого
31 /// объекта.</param>
32 /// <remarks>
33 /// Данный метод осуществляет проверку того, что объект уже был освобожден, чтобы не вызывать
34 /// событие <see cref="Disposed"/>. Не поддерживает многопоточность.
35 /// </remarks>
23 protected virtual void Dispose(bool disposing) {
36 protected virtual void Dispose(bool disposing) {
24 if (disposing && !m_disposed) {
37 if (disposing && !m_disposed) {
25 m_disposed = true;
38 m_disposed = true;
26
39
27 EventHandler temp = Disposed;
40 EventHandler temp = Disposed;
28 if (temp != null)
41 if (temp != null)
29 temp(this,EventArgs.Empty);
42 temp(this,EventArgs.Empty);
30 }
43 }
31 }
44 }
32 public void Dispose() {
45 public void Dispose() {
33 Dispose(true);
46 Dispose(true);
34 GC.SuppressFinalize(this);
47 GC.SuppressFinalize(this);
35 }
48 }
36
49
50 /// <summary>
51 /// Записывает сообщение об утечке объекта.
52 /// </summary>
37 protected virtual void ReportObjectLeaks() {
53 protected virtual void ReportObjectLeaks() {
38 Trace.TraceWarning("The object is marked as disposable but isn't disposed properly: {0}", this);
54 TraceLog.TraceWarning("The object is marked as disposable but isn't disposed properly: {0}", this);
39 }
55 }
40
56
41 ~Disposable() {
57 ~Disposable() {
42 Dispose(false);
58 Dispose(false);
43 ReportObjectLeaks();
59 ReportObjectLeaks();
44 }
60 }
45 }
61 }
46 } No newline at end of file
62 }
@@ -1,71 +1,70
1 <?xml version="1.0" encoding="utf-8"?>
1 <?xml version="1.0" encoding="utf-8"?>
2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <PropertyGroup>
3 <PropertyGroup>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 <ProductVersion>10.0.0</ProductVersion>
6 <ProductVersion>10.0.0</ProductVersion>
7 <SchemaVersion>2.0</SchemaVersion>
7 <SchemaVersion>2.0</SchemaVersion>
8 <ProjectGuid>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</ProjectGuid>
8 <ProjectGuid>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</ProjectGuid>
9 <OutputType>Library</OutputType>
9 <OutputType>Library</OutputType>
10 <RootNamespace>Implab</RootNamespace>
10 <RootNamespace>Implab</RootNamespace>
11 <AssemblyName>Implab</AssemblyName>
11 <AssemblyName>Implab</AssemblyName>
12 </PropertyGroup>
12 </PropertyGroup>
13 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
13 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
14 <DebugSymbols>true</DebugSymbols>
14 <DebugSymbols>true</DebugSymbols>
15 <DebugType>full</DebugType>
15 <DebugType>full</DebugType>
16 <Optimize>false</Optimize>
16 <Optimize>false</Optimize>
17 <OutputPath>bin\Debug</OutputPath>
17 <OutputPath>bin\Debug</OutputPath>
18 <DefineConstants>TRACE;DEBUG;</DefineConstants>
18 <DefineConstants>TRACE;DEBUG;</DefineConstants>
19 <ErrorReport>prompt</ErrorReport>
19 <ErrorReport>prompt</ErrorReport>
20 <WarningLevel>4</WarningLevel>
20 <WarningLevel>4</WarningLevel>
21 <ConsolePause>false</ConsolePause>
21 <ConsolePause>false</ConsolePause>
22 </PropertyGroup>
22 </PropertyGroup>
23 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
23 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
24 <DebugType>full</DebugType>
24 <DebugType>full</DebugType>
25 <Optimize>true</Optimize>
25 <Optimize>true</Optimize>
26 <OutputPath>bin\Release</OutputPath>
26 <OutputPath>bin\Release</OutputPath>
27 <ErrorReport>prompt</ErrorReport>
27 <ErrorReport>prompt</ErrorReport>
28 <WarningLevel>4</WarningLevel>
28 <WarningLevel>4</WarningLevel>
29 <ConsolePause>false</ConsolePause>
29 <ConsolePause>false</ConsolePause>
30 </PropertyGroup>
30 </PropertyGroup>
31 <ItemGroup>
31 <ItemGroup>
32 <Reference Include="System" />
32 <Reference Include="System" />
33 </ItemGroup>
33 </ItemGroup>
34 <ItemGroup>
34 <ItemGroup>
35 <Compile Include="Component.cs" />
35 <Compile Include="Component.cs" />
36 <Compile Include="Diagnostics\ConsoleTraceListener.cs" />
36 <Compile Include="Diagnostics\ConsoleTraceListener.cs" />
37 <Compile Include="Diagnostics\EventText.cs" />
37 <Compile Include="Diagnostics\EventText.cs" />
38 <Compile Include="Diagnostics\IEventTextFormatter.cs" />
38 <Compile Include="Diagnostics\IEventTextFormatter.cs" />
39 <Compile Include="Diagnostics\LogChannel.cs" />
39 <Compile Include="Diagnostics\LogChannel.cs" />
40 <Compile Include="Diagnostics\LogicalOperation.cs" />
40 <Compile Include="Diagnostics\LogicalOperation.cs" />
41 <Compile Include="Diagnostics\TextFileListener.cs" />
41 <Compile Include="Diagnostics\TextFileListener.cs" />
42 <Compile Include="Diagnostics\TextListenerBase.cs" />
42 <Compile Include="Diagnostics\TextListenerBase.cs" />
43 <Compile Include="Diagnostics\TraceLog.cs" />
43 <Compile Include="Diagnostics\TraceLog.cs" />
44 <Compile Include="Diagnostics\TraceContext.cs" />
44 <Compile Include="Diagnostics\TraceContext.cs" />
45 <Compile Include="Diagnostics\TraceEvent.cs" />
45 <Compile Include="Diagnostics\TraceEvent.cs" />
46 <Compile Include="Diagnostics\TraceEventType.cs" />
46 <Compile Include="Diagnostics\TraceEventType.cs" />
47 <Compile Include="Disposable.cs" />
47 <Compile Include="Disposable.cs" />
48 <Compile Include="ICancellable.cs" />
48 <Compile Include="ICancellable.cs" />
49 <Compile Include="IProgressHandler.cs" />
49 <Compile Include="IProgressHandler.cs" />
50 <Compile Include="IProgressNotifier.cs" />
50 <Compile Include="IProgressNotifier.cs" />
51 <Compile Include="IPromise.cs" />
51 <Compile Include="IPromise.cs" />
52 <Compile Include="IPromiseBase.cs" />
52 <Compile Include="IPromiseBase.cs" />
53 <Compile Include="IServiceLocator.cs" />
53 <Compile Include="IServiceLocator.cs" />
54 <Compile Include="ITaskController.cs" />
54 <Compile Include="ITaskController.cs" />
55 <Compile Include="ManagedPromise.cs" />
56 <Compile Include="Parallels\DispatchPool.cs" />
55 <Compile Include="Parallels\DispatchPool.cs" />
57 <Compile Include="Parallels\ArrayTraits.cs" />
56 <Compile Include="Parallels\ArrayTraits.cs" />
58 <Compile Include="Parallels\MTQueue.cs" />
57 <Compile Include="Parallels\MTQueue.cs" />
59 <Compile Include="Parallels\WorkerPool.cs" />
58 <Compile Include="Parallels\WorkerPool.cs" />
60 <Compile Include="ServiceLocator.cs" />
59 <Compile Include="ServiceLocator.cs" />
61 <Compile Include="TaskController.cs" />
60 <Compile Include="TaskController.cs" />
62 <Compile Include="ProgressInitEventArgs.cs" />
61 <Compile Include="ProgressInitEventArgs.cs" />
63 <Compile Include="Properties\AssemblyInfo.cs" />
62 <Compile Include="Properties\AssemblyInfo.cs" />
64 <Compile Include="Promise.cs" />
63 <Compile Include="Promise.cs" />
65 <Compile Include="Parallels\AsyncPool.cs" />
64 <Compile Include="Parallels\AsyncPool.cs" />
66 <Compile Include="Safe.cs" />
65 <Compile Include="Safe.cs" />
67 <Compile Include="ValueEventArgs.cs" />
66 <Compile Include="ValueEventArgs.cs" />
68 </ItemGroup>
67 </ItemGroup>
69 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
68 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
70 <ItemGroup />
69 <ItemGroup />
71 </Project> No newline at end of file
70 </Project>
@@ -1,191 +1,191
1 using Implab.Diagnostics;
1 using Implab.Diagnostics;
2 using System;
2 using System;
3 using System.Collections.Generic;
3 using System.Collections.Generic;
4 using System.Diagnostics;
4 using System.Diagnostics;
5 using System.Linq;
5 using System.Linq;
6 using System.Text;
6 using System.Text;
7 using System.Threading;
7 using System.Threading;
8
8
9 namespace Implab.Parallels {
9 namespace Implab.Parallels {
10 public static class ArrayTraits {
10 public static class ArrayTraits {
11 class ArrayIterator<TSrc> : DispatchPool<int> {
11 class ArrayIterator<TSrc> : DispatchPool<int> {
12 readonly Action<TSrc> m_action;
12 readonly Action<TSrc> m_action;
13 readonly TSrc[] m_source;
13 readonly TSrc[] m_source;
14 readonly Promise<int> m_promise = new Promise<int>();
14 readonly Promise<int> m_promise = new Promise<int>();
15 readonly TraceContext m_traceContext;
15 readonly TraceContext m_traceContext;
16
16
17 int m_pending;
17 int m_pending;
18 int m_next;
18 int m_next;
19
19
20 public ArrayIterator(TSrc[] source, Action<TSrc> action, int threads)
20 public ArrayIterator(TSrc[] source, Action<TSrc> action, int threads)
21 : base(threads) {
21 : base(threads) {
22
22
23 Debug.Assert(source != null);
23 Debug.Assert(source != null);
24 Debug.Assert(action != null);
24 Debug.Assert(action != null);
25
25
26 m_traceContext = TraceContext.Snapshot();
26 m_traceContext = TraceContext.Snapshot();
27 m_next = 0;
27 m_next = 0;
28 m_source = source;
28 m_source = source;
29 m_pending = source.Length;
29 m_pending = source.Length;
30 m_action = action;
30 m_action = action;
31
31
32 m_promise.Anyway(() => Dispose());
32 m_promise.Anyway(() => Dispose());
33 m_promise.Cancelled(() => Dispose());
33 m_promise.Cancelled(() => Dispose());
34
34
35 InitPool();
35 InitPool();
36 }
36 }
37
37
38 public Promise<int> Promise {
38 public Promise<int> Promise {
39 get {
39 get {
40 return m_promise;
40 return m_promise;
41 }
41 }
42 }
42 }
43
43
44 protected override void Worker() {
44 protected override void Worker() {
45 TraceContext.Transfer(m_traceContext);
45 TraceContext.Fork(m_traceContext);
46 base.Worker();
46 base.Worker();
47 }
47 }
48
48
49 protected override bool TryDequeue(out int unit) {
49 protected override bool TryDequeue(out int unit) {
50 unit = Interlocked.Increment(ref m_next) - 1;
50 unit = Interlocked.Increment(ref m_next) - 1;
51 return unit >= m_source.Length ? false : true;
51 return unit >= m_source.Length ? false : true;
52 }
52 }
53
53
54 protected override void InvokeUnit(int unit) {
54 protected override void InvokeUnit(int unit) {
55 try {
55 try {
56 m_action(m_source[unit]);
56 m_action(m_source[unit]);
57 var pending = Interlocked.Decrement(ref m_pending);
57 var pending = Interlocked.Decrement(ref m_pending);
58 if (pending == 0)
58 if (pending == 0)
59 m_promise.Resolve(m_source.Length);
59 m_promise.Resolve(m_source.Length);
60 } catch (Exception e) {
60 } catch (Exception e) {
61 m_promise.Reject(e);
61 m_promise.Reject(e);
62 }
62 }
63 }
63 }
64 }
64 }
65
65
66 class ArrayMapper<TSrc, TDst>: DispatchPool<int> {
66 class ArrayMapper<TSrc, TDst>: DispatchPool<int> {
67 readonly Func<TSrc, TDst> m_transform;
67 readonly Func<TSrc, TDst> m_transform;
68 readonly TSrc[] m_source;
68 readonly TSrc[] m_source;
69 readonly TDst[] m_dest;
69 readonly TDst[] m_dest;
70 readonly Promise<TDst[]> m_promise = new Promise<TDst[]>();
70 readonly Promise<TDst[]> m_promise = new Promise<TDst[]>();
71 readonly TraceContext m_traceContext;
71 readonly TraceContext m_traceContext;
72
72
73 int m_pending;
73 int m_pending;
74 int m_next;
74 int m_next;
75
75
76 public ArrayMapper(TSrc[] source, Func<TSrc, TDst> transform, int threads)
76 public ArrayMapper(TSrc[] source, Func<TSrc, TDst> transform, int threads)
77 : base(threads) {
77 : base(threads) {
78
78
79 Debug.Assert (source != null);
79 Debug.Assert (source != null);
80 Debug.Assert( transform != null);
80 Debug.Assert( transform != null);
81
81
82 m_next = 0;
82 m_next = 0;
83 m_source = source;
83 m_source = source;
84 m_dest = new TDst[source.Length];
84 m_dest = new TDst[source.Length];
85 m_pending = source.Length;
85 m_pending = source.Length;
86 m_transform = transform;
86 m_transform = transform;
87 m_traceContext = TraceContext.Snapshot();
87 m_traceContext = TraceContext.Snapshot();
88
88
89 m_promise.Anyway(() => Dispose());
89 m_promise.Anyway(() => Dispose());
90 m_promise.Cancelled(() => Dispose());
90 m_promise.Cancelled(() => Dispose());
91
91
92 InitPool();
92 InitPool();
93 }
93 }
94
94
95 public Promise<TDst[]> Promise {
95 public Promise<TDst[]> Promise {
96 get {
96 get {
97 return m_promise;
97 return m_promise;
98 }
98 }
99 }
99 }
100
100
101 protected override void Worker() {
101 protected override void Worker() {
102 TraceContext.Transfer(m_traceContext);
102 TraceContext.Fork(m_traceContext);
103 base.Worker();
103 base.Worker();
104 }
104 }
105
105
106 protected override bool TryDequeue(out int unit) {
106 protected override bool TryDequeue(out int unit) {
107 unit = Interlocked.Increment(ref m_next) - 1;
107 unit = Interlocked.Increment(ref m_next) - 1;
108 return unit >= m_source.Length ? false : true;
108 return unit >= m_source.Length ? false : true;
109 }
109 }
110
110
111 protected override void InvokeUnit(int unit) {
111 protected override void InvokeUnit(int unit) {
112 try {
112 try {
113 m_dest[unit] = m_transform(m_source[unit]);
113 m_dest[unit] = m_transform(m_source[unit]);
114 var pending = Interlocked.Decrement(ref m_pending);
114 var pending = Interlocked.Decrement(ref m_pending);
115 if (pending == 0)
115 if (pending == 0)
116 m_promise.Resolve(m_dest);
116 m_promise.Resolve(m_dest);
117 } catch (Exception e) {
117 } catch (Exception e) {
118 m_promise.Reject(e);
118 m_promise.Reject(e);
119 }
119 }
120 }
120 }
121 }
121 }
122
122
123 public static IPromise<TDst[]> ParallelMap<TSrc, TDst> (this TSrc[] source, Func<TSrc,TDst> transform, int threads) {
123 public static IPromise<TDst[]> ParallelMap<TSrc, TDst> (this TSrc[] source, Func<TSrc,TDst> transform, int threads) {
124 if (source == null)
124 if (source == null)
125 throw new ArgumentNullException("source");
125 throw new ArgumentNullException("source");
126 if (transform == null)
126 if (transform == null)
127 throw new ArgumentNullException("transform");
127 throw new ArgumentNullException("transform");
128
128
129 var mapper = new ArrayMapper<TSrc, TDst>(source, transform, threads);
129 var mapper = new ArrayMapper<TSrc, TDst>(source, transform, threads);
130 return mapper.Promise;
130 return mapper.Promise;
131 }
131 }
132
132
133 public static IPromise<int> ParallelForEach<TSrc>(this TSrc[] source, Action<TSrc> action, int threads) {
133 public static IPromise<int> ParallelForEach<TSrc>(this TSrc[] source, Action<TSrc> action, int threads) {
134 if (source == null)
134 if (source == null)
135 throw new ArgumentNullException("source");
135 throw new ArgumentNullException("source");
136 if (action == null)
136 if (action == null)
137 throw new ArgumentNullException("action");
137 throw new ArgumentNullException("action");
138
138
139 var iter = new ArrayIterator<TSrc>(source, action, threads);
139 var iter = new ArrayIterator<TSrc>(source, action, threads);
140 return iter.Promise;
140 return iter.Promise;
141 }
141 }
142
142
143 public static IPromise<TDst[]> ChainedMap<TSrc, TDst>(this TSrc[] source, ChainedOperation<TSrc, TDst> transform, int threads) {
143 public static IPromise<TDst[]> ChainedMap<TSrc, TDst>(this TSrc[] source, ChainedOperation<TSrc, TDst> transform, int threads) {
144 if (source == null)
144 if (source == null)
145 throw new ArgumentNullException("source");
145 throw new ArgumentNullException("source");
146 if (transform == null)
146 if (transform == null)
147 throw new ArgumentNullException("transform");
147 throw new ArgumentNullException("transform");
148 if (threads <= 0)
148 if (threads <= 0)
149 throw new ArgumentOutOfRangeException("Threads number must be greater then zero");
149 throw new ArgumentOutOfRangeException("Threads number must be greater then zero");
150
150
151 if (source.Length == 0)
151 if (source.Length == 0)
152 return Promise<TDst[]>.ResultToPromise(new TDst[0]);
152 return Promise<TDst[]>.ResultToPromise(new TDst[0]);
153
153
154 var promise = new Promise<TDst[]>();
154 var promise = new Promise<TDst[]>();
155 var res = new TDst[source.Length];
155 var res = new TDst[source.Length];
156 var pending = source.Length;
156 var pending = source.Length;
157
157
158 var semaphore = new Semaphore(threads, threads);
158 var semaphore = new Semaphore(threads, threads);
159
159
160 AsyncPool.InvokeNewThread(() => {
160 AsyncPool.InvokeNewThread(() => {
161 for (int i = 0; i < source.Length; i++) {
161 for (int i = 0; i < source.Length; i++) {
162 if(promise.IsResolved)
162 if(promise.IsResolved)
163 break; // stop processing in case of error or cancellation
163 break; // stop processing in case of error or cancellation
164 var idx = i;
164 var idx = i;
165 semaphore.WaitOne();
165 semaphore.WaitOne();
166 try {
166 try {
167 var p1 = transform(source[i]);
167 var p1 = transform(source[i]);
168 p1.Anyway(() => semaphore.Release());
168 p1.Anyway(() => semaphore.Release());
169 p1.Cancelled(() => semaphore.Release());
169 p1.Cancelled(() => semaphore.Release());
170 p1.Then(
170 p1.Then(
171 x => {
171 x => {
172 res[idx] = x;
172 res[idx] = x;
173 var left = Interlocked.Decrement(ref pending);
173 var left = Interlocked.Decrement(ref pending);
174 if (left == 0)
174 if (left == 0)
175 promise.Resolve(res);
175 promise.Resolve(res);
176 },
176 },
177 e => promise.Reject(e)
177 e => promise.Reject(e)
178 );
178 );
179
179
180 } catch (Exception e) {
180 } catch (Exception e) {
181 promise.Reject(e);
181 promise.Reject(e);
182 }
182 }
183 }
183 }
184 return 0;
184 return 0;
185 });
185 });
186
186
187 return promise.Anyway(() => semaphore.Dispose());
187 return promise.Anyway(() => semaphore.Dispose());
188 }
188 }
189
189
190 }
190 }
191 }
191 }
@@ -1,50 +1,71
1 using Implab.Diagnostics;
1 using Implab.Diagnostics;
2 using System;
2 using System;
3 using System.Threading;
3 using System.Threading;
4
4
5 namespace Implab.Parallels {
5 namespace Implab.Parallels {
6 /// <summary>
6 /// <summary>
7 /// Класс для распаралеливания задач.
7 /// Класс для распаралеливания задач.
8 /// </summary>
8 /// </summary>
9 /// <remarks>
9 /// <remarks>
10 /// Используя данный класс и лямда выражения можно распараллелить
10 /// Используя данный класс и лямда выражения можно распараллелить
11 /// вычисления, для этого используется концепция обещаний.
11 /// вычисления, для этого используется концепция обещаний.
12 /// </remarks>
12 /// </remarks>
13 public static class AsyncPool {
13 public static class AsyncPool {
14
14
15 public static Promise<T> Invoke<T>(Func<T> func) {
15 public static IPromise<T> Invoke<T>(Func<T> func) {
16 var p = new Promise<T>();
16 var p = new Promise<T>();
17 var caller = TraceContext.Snapshot();
17 var caller = TraceContext.Snapshot();
18
18
19 ThreadPool.QueueUserWorkItem(param => {
19 ThreadPool.QueueUserWorkItem(param => {
20 TraceContext.Transfer(caller);
20 TraceContext.Fork(caller);
21 try {
21 try {
22 p.Resolve(func());
22 p.Resolve(func());
23 } catch(Exception e) {
23 } catch(Exception e) {
24 p.Reject(e);
24 p.Reject(e);
25 }
25 }
26 });
26 });
27
27
28 return p;
28 return p;
29 }
29 }
30
30
31 public static Promise<T> InvokeNewThread<T>(Func<T> func) {
31 public static IPromise<T> InvokeNewThread<T>(Func<T> func) {
32 var p = new Promise<T>();
32 var p = new Promise<T>();
33
33
34 var caller = TraceContext.Snapshot();
34 var caller = TraceContext.Snapshot();
35
35
36 var worker = new Thread(() => {
36 var worker = new Thread(() => {
37 TraceContext.Transfer(caller);
37 TraceContext.Fork(caller);
38 try {
38 try {
39 p.Resolve(func());
39 p.Resolve(func());
40 } catch (Exception e) {
40 } catch (Exception e) {
41 p.Reject(e);
41 p.Reject(e);
42 }
42 }
43 });
43 });
44 worker.IsBackground = true;
44 worker.IsBackground = true;
45 worker.Start();
45 worker.Start();
46
46
47 return p;
47 return p;
48 }
48 }
49
50
51 public static IPromiseBase InvokeNewThread(Action func) {
52 var p = new Promise<object>();
53
54 var caller = TraceContext.Snapshot();
55
56 var worker = new Thread(() => {
57 TraceContext.Fork(caller);
58 try {
59 func();
60 p.Resolve();
61 } catch (Exception e) {
62 p.Reject(e);
63 }
64 });
65 worker.IsBackground = true;
66 worker.Start();
67
68 return p;
49 }
69 }
50 }
70 }
71 }
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now