##// 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 1 syntax: glob
2 2 Implab.Test/bin/
3 3 *.user
4 4 Implab.Test/obj/
5 5 *.userprefs
6 6 Implab/bin/
7 7 Implab/obj/
8 8 TestResults/
9 9 Implab.Fx/obj/
10 10 Implab.Fx/bin/
11 11 Implab.Fx.Test/bin/
12 12 Implab.Fx.Test/obj/
13 13 _ReSharper.Implab/
14 Implab.Diagnostics.Interactive/bin/
15 Implab.Diagnostics.Interactive/obj/
@@ -1,34 +1,34
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5
6 6 namespace Implab.Diagnostics {
7 7 public class ConsoleTraceListener: TextListenerBase {
8 8
9 9 static readonly object _consoleLock = new object();
10 10
11 11 public ConsoleTraceListener()
12 12 : base(true) {
13 13
14 14 }
15 15
16 public ConsoleTraceListener(bool local)
17 : base(local) {
16 public ConsoleTraceListener(bool global)
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 22 var msg = new StringBuilder();
23 23
24 24 for (int i = 0; i < text.indent; i++)
25 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 28 lock (_consoleLock) {
29 29 Console.ForegroundColor = (ConsoleColor)(context.ThreadId % 15 + 1);
30 30 Console.WriteLine(msg.ToString());
31 31 }
32 32 }
33 33 }
34 34 }
@@ -1,30 +1,81
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5
6 6 namespace Implab.Diagnostics {
7 /// <summary>
8 /// Канал, через который публикуются события журнала.
9 /// </summary>
10 /// <typeparam name="TEvent">Тип событий в канале</typeparam>
11 /// <remarks>
12 /// Событиями журнала могут быть любые типы, например строки, в которых будет передаваться
13 /// информация, или структуры с набором полей, описывающих важность, текст и другую информацию.
14 /// </remarks>
7 15 public class LogChannel<TEvent> {
8 16 static LogChannel<TEvent> _default = new LogChannel<TEvent>();
9 17
18 /// <summary>
19 /// Канал по-умолчанию для событий типа <typeparam name="TEvent"/>.
20 /// </summary>
10 21 public static LogChannel<TEvent> Default {
11 22 get {
12 23 return _default;
13 24 }
14 25 }
15 26
27 /// <summary>
28 /// Событие появление новой записи в журнале, на это событие подписываются слушатели.
29 /// </summary>
16 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 64 public void LogEvent(TEvent data) {
19 65 var t = Events;
20 66 if (t!= null)
21 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 75 public void LogEvent(TraceContext context,TEvent data) {
25 76 var t = Events;
26 77 if (t != null)
27 78 t(context, new ValueEventArgs<TEvent>(data));
28 79 }
29 80 }
30 81 }
@@ -1,44 +1,47
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.IO;
4 4 using System.Linq;
5 5 using System.Text;
6 6
7 7 namespace Implab.Diagnostics {
8 8 public class TextFileListener: TextListenerBase {
9 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 13 m_textWriter = File.CreateText(fileName);
13 14
14 15 m_textWriter.WriteLine("LOG {0}", DateTime.Now);
15 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 20 var msg = new StringBuilder();
20 21 for (int i = 0; i < text.indent; i++)
21 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 25 lock (m_textWriter) {
25 26 if (!IsDisposed) {
27 // тут гарантировано еще не освобожден m_textWriter
26 28 m_textWriter.WriteLine(msg.ToString());
27 29 m_textWriter.Flush();
28 30 }
29 31 }
30 32 }
31 33
32 34
33 35 protected override void Dispose(bool disposing) {
34 36 base.Dispose(disposing);
35 37 if (disposing) {
38 // IsDisposed = true
36 39 lock (m_textWriter) {
37 40 Safe.Dispose(m_textWriter);
38 41 }
39 42 }
40 43 }
41 44
42 45
43 46 }
44 47 }
@@ -1,119 +1,129
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5
6 6 namespace Implab.Diagnostics {
7 7 public abstract class TextListenerBase : ServiceLocator, IEventTextFormatter<object>, IEventTextFormatter<TraceEvent> {
8 8
9 9 readonly Dictionary<object, Action> m_subscriptions = new Dictionary<object, Action>();
10 10 readonly LogicalOperation m_boundOperation;
11 11 readonly int m_baseIndent;
12 12
13 protected TextListenerBase(bool local) {
13 protected TextListenerBase(bool global) {
14 14 Register(this);
15 if (local) {
15 if (!global) {
16 16 m_boundOperation = TraceContext.Current.CurrentOperation;
17 17 m_baseIndent = Math.Max(0, m_boundOperation.Level - 1);
18 18 }
19 19 }
20 20
21 21 public void Subscribe(Type eventType) {
22 22 if (eventType == null)
23 23 throw new ArgumentNullException("eventType");
24 24 GetType().GetMethod("Subscribe", new Type[0]).MakeGenericMethod(eventType).Invoke(this, null);
25 25 }
26 26
27 27 public void Subscribe<TEvent>() {
28 28 Subscribe<TEvent>(LogChannel<TEvent>.Default);
29 29 }
30 30
31 31 public void Subscribe<TEvent>(LogChannel<TEvent> channel) {
32 32 if (channel == null)
33 33 throw new ArgumentNullException("channel");
34 34
35 35 lock (m_subscriptions) {
36 36 AssertNotDisposed();
37 37
38 38 var formatter = GetService<IEventTextFormatter<TEvent>>();
39 var channelName = channel.Name;
39 40
40 41 EventHandler<ValueEventArgs<TEvent>> handler = (sender, args) => {
41 42 TraceContext context = (TraceContext)sender;
42 43 var text = formatter.Format(context, args.Value);
43 44 text.indent -= m_baseIndent;
44 45
45 46 if (IsRelated(context.CurrentOperation))
46 WriteEntry(context, text);
47 WriteEntry(context, text, channelName);
47 48 };
48 49
49 50 if (m_subscriptions.ContainsKey(channel))
50 51 return;
51 52
52 53 channel.Events += handler;
53 54
54 55 Action unsubscribe = () => {
55 56 channel.Events -= handler;
56 57 };
57 58
58 59 m_subscriptions.Add(channel, unsubscribe);
59 60 }
60 61 }
61 62
62 63 public bool IsRelated(LogicalOperation op) {
63 64 if (m_boundOperation == null)
64 65 return true;
65 66
66 67 while (op != m_boundOperation && op.Level > m_boundOperation.Level)
67 68 op = op.Parent;
68 69 return op == m_boundOperation;
69 70 }
70 71
71 72 public void Unsubscribe<TEvent>(LogChannel<TEvent> channel) {
72 73 if (channel == null)
73 74 throw new ArgumentNullException("channel");
74 75
75 76 lock (m_subscriptions) {
76 77 Action subscription;
77 78 if (m_subscriptions.TryGetValue(channel, out subscription)) {
78 79 subscription();
79 80 m_subscriptions.Remove(channel);
80 81 }
81 82 }
82 83 }
83 84
84 85 public void UnsubscribeAll() {
85 86 lock (m_subscriptions) {
86 87 foreach (var subscription in m_subscriptions.Values)
87 88 subscription();
88 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 104 public EventText Format(TraceContext context, object data) {
95 105 return new EventText {
96 106 indent = context.CurrentOperation.Level,
97 107 content = data.ToString()
98 108 };
99 109 }
100 110
101 111 public EventText Format(TraceContext context, TraceEvent data) {
102 112 var level = context.CurrentOperation.Level;
103 113 if (data.EventType == TraceEventType.OperationCompleted || data.EventType == TraceEventType.OperationStarted)
104 114 level--;
105 115
106 116 return new EventText {
107 117 indent = level,
108 118 content = data.ToString()
109 119 };
110 120 }
111 121
112 122 protected override void Dispose(bool disposing) {
123 base.Dispose(disposing);
113 124 if (disposing) {
114 125 UnsubscribeAll();
115 126 }
116 base.Dispose(disposing);
117 127 }
118 128 }
119 129 }
@@ -1,172 +1,211
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5 using System.Threading;
6 6 using System.Threading.Tasks;
7 7
8 8 namespace Implab.Diagnostics {
9 9 /// <summary>
10 10 /// Контекст трассировки, привязывается к потоку и содержит в себе информацию о стеке логических операций.
11 11 /// </summary>
12 12 /// <remarks>
13 13 /// Контекст трассировки передается слушателям событий для определения места, где возникло событие.
14 14 /// </remarks>
15 15 public class TraceContext {
16 16 LogicalOperation m_currentOperation;
17 17 readonly LogicalOperation m_bound;
18 18 readonly int m_threadId;
19 19
20 20 [ThreadStatic]
21 21 static TraceContext _current;
22 22
23 23 /// <summary>
24 24 /// Текущий контекст трассировки для потока, создается астоматически при первом обращении.
25 25 /// </summary>
26 26 public static TraceContext Current {
27 27 get {
28 if (_current == null)
28 if (_current == null) {
29 29 _current = new TraceContext();
30 _current.LogEvent(TraceEventType.Created,"[{0}]", _current.ThreadId);
31 }
30 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 41 if (context == null)
36 42 throw new ArgumentNullException("context");
37 43
38 44 m_currentOperation = context.CurrentOperation;
39 m_bound = context.CurrentOperation;
45 m_bound = attach ? context.BoundOperation : context.CurrentOperation;
40 46 m_threadId = Thread.CurrentThread.ManagedThreadId;
41 47 }
42 48
43 49 TraceContext() {
44 50 m_currentOperation = new LogicalOperation();
45 51 m_bound = m_currentOperation;
46 52 m_threadId = Thread.CurrentThread.ManagedThreadId;
47 53 }
48 54
49 55 /// <summary>
50 56 /// При необходимости копирует состояние контекста трассивровки в текущий поток.
51 57 /// </summary>
52 58 /// <param name="from">Исходный контекст трассировки, который передается.</param>
53 59 /// <remarks>
54 60 /// <para>
55 61 /// Копирование происходит за счет создания нового контекста трассировки и заполнением его
56 62 /// состояния из переданного контекста. При этом копируется стек операций, однако в новом
57 63 /// контексте ранее начатые логические операции не могут быть завершены.
58 64 /// </para>
59 65 /// <para>
60 /// Если передача состояния состоялась, то вызывается событие трассировки <see cref="TraceEventType.Transfer"/>.
66 /// Если передача состояния состоялась, то вызывается событие трассировки <see cref="TraceEventType.Fork"/>.
61 67 /// </para>
62 68 /// </remarks>
63 public static void Transfer(TraceContext from) {
69 public static void Fork(TraceContext from) {
64 70 if (_current == from)
65 71 return;
66 72 if (from != null) {
67 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 75 _current = context;
70 76 } else {
71 77 _current = new TraceContext();
72 78 }
73 79 }
74 80
75 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 116 /// </summary>
78 117 /// <returns>Копия текущего контекста трассировки.</returns>
79 118 public static TraceContext Snapshot() {
80 119 return _current == null ? new TraceContext() : new TraceContext(_current);
81 120 }
82 121
83 122 /// <summary>
84 123 /// Выполняет переданное действие в указанном контексте трассировки, по окончании восстанавливает предыдущий контекст трассировки потока.
85 124 /// </summary>
86 125 /// <param name="action"></param>
87 126 public void Invoke(Action action) {
88 127 if (action == null)
89 128 throw new ArgumentNullException("action");
90 129 var old = _current;
91 Transfer(this);
130 Fork(this);
92 131 try {
93 132 action();
94 133 } finally {
95 134 _current.EndAllOperations();
96 135 _current = old;
97 136 }
98 137 }
99 138
100 139 /// <summary>
101 140 /// Текущая логическая операция.
102 141 /// </summary>
103 142 public LogicalOperation CurrentOperation {
104 143 get {
105 144 return m_currentOperation;
106 145 }
107 146 }
108 147
109 148 /// <summary>
110 149 /// Операция ниже которой нельзя опускаться в стеке логических операций, т.е. она не может быть завершена в текущем контексте.
111 150 /// </summary>
112 151 public LogicalOperation BoundOperation {
113 152 get {
114 153 return m_bound;
115 154 }
116 155 }
117 156
118 157 /// <summary>
119 158 /// Поток, в котором создан контекст трассировки.
120 159 /// </summary>
121 160 public int ThreadId {
122 161 get {
123 162 return m_threadId;
124 163 }
125 164 }
126 165
127 166 /// <summary>
128 167 /// Начинает безымянную логическую операцию.
129 168 /// </summary>
130 169 public void StartLogicalOperation() {
131 170 StartLogicalOperation(null);
132 171 }
133 172
134 173 /// <summary>
135 174 /// Начинает логическую операцию с указанным именем. Созданная операция будет добвалена в стек логических операций контекста, затем будет создано соответсвующее событие.
136 175 /// </summary>
137 176 /// <param name="name">Имя начинаемой операции.</param>
138 177 public void StartLogicalOperation(string name) {
139 178 m_currentOperation = new LogicalOperation(name, m_currentOperation);
140 179 LogEvent(TraceEventType.OperationStarted, name);
141 180 }
142 181
143 182 /// <summary>
144 183 /// Заканчивает логическую операцию начатую в текущем контексте. Операции, начатые в других контекстах не могут быть закончены в текущем контексте.
145 184 /// </summary>
146 185 /// <remarks>
147 186 /// При вызове данного метода создается событие журнала трассировки, либо о завершении операции, либо об ошибки, поскольку данная операция
148 187 /// начата в другом контексте.
149 188 /// </remarks>
150 189 public void EndLogicalOperation() {
151 190 if (m_bound == m_currentOperation) {
152 191 LogEvent(TraceEventType.Error, "Trying to end the operation which isn't belongs to current trace");
153 192 } else {
154 193 var op = m_currentOperation;
155 194 LogEvent(TraceEventType.OperationCompleted, "{0} {1} ms", op.Name, op.Duration);
156 195 m_currentOperation = m_currentOperation.Parent;
157 196 }
158 197 }
159 198
160 199 /// <summary>
161 200 /// Заврешает все начатые в этом контексте операции
162 201 /// </summary>
163 202 public void EndAllOperations() {
164 203 while (m_bound != m_currentOperation)
165 204 EndLogicalOperation();
166 205 }
167 206
168 207 void LogEvent(TraceEventType type, string format, params object[] args) {
169 208 LogChannel<TraceEvent>.Default.LogEvent(this, TraceEvent.Create(type, format, args));
170 209 }
171 210 }
172 211 }
@@ -1,16 +1,19
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5 using System.Threading.Tasks;
6 6
7 7 namespace Implab.Diagnostics {
8 8 public enum TraceEventType {
9 9 Information = 1,
10 10 Warning,
11 11 Error,
12 12 OperationStarted,
13 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 3 using System.Collections.Generic;
3 4 using System.Diagnostics;
4 5 using System.Linq;
5 6 using System.Web;
6 7
7 8 namespace Implab {
9 /// <summary>
10 /// Объект, поддерживающий освобождение ресурсов.
11 /// </summary>
8 12 public class Disposable : IDisposable {
9 13
10 14 bool m_disposed;
11 15
12 16 public event EventHandler Disposed;
13 17
14 18 public bool IsDisposed {
15 19 get { return m_disposed; }
16 20 }
17 21
18 22 protected void AssertNotDisposed() {
19 23 if (m_disposed)
20 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 36 protected virtual void Dispose(bool disposing) {
24 37 if (disposing && !m_disposed) {
25 38 m_disposed = true;
26 39
27 40 EventHandler temp = Disposed;
28 41 if (temp != null)
29 42 temp(this,EventArgs.Empty);
30 43 }
31 44 }
32 45 public void Dispose() {
33 46 Dispose(true);
34 47 GC.SuppressFinalize(this);
35 48 }
36 49
50 /// <summary>
51 /// Записывает сообщение об утечке объекта.
52 /// </summary>
37 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 57 ~Disposable() {
42 58 Dispose(false);
43 59 ReportObjectLeaks();
44 60 }
45 61 }
46 62 } No newline at end of file
@@ -1,71 +1,70
1 1 <?xml version="1.0" encoding="utf-8"?>
2 2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 3 <PropertyGroup>
4 4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 6 <ProductVersion>10.0.0</ProductVersion>
7 7 <SchemaVersion>2.0</SchemaVersion>
8 8 <ProjectGuid>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</ProjectGuid>
9 9 <OutputType>Library</OutputType>
10 10 <RootNamespace>Implab</RootNamespace>
11 11 <AssemblyName>Implab</AssemblyName>
12 12 </PropertyGroup>
13 13 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
14 14 <DebugSymbols>true</DebugSymbols>
15 15 <DebugType>full</DebugType>
16 16 <Optimize>false</Optimize>
17 17 <OutputPath>bin\Debug</OutputPath>
18 18 <DefineConstants>TRACE;DEBUG;</DefineConstants>
19 19 <ErrorReport>prompt</ErrorReport>
20 20 <WarningLevel>4</WarningLevel>
21 21 <ConsolePause>false</ConsolePause>
22 22 </PropertyGroup>
23 23 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
24 24 <DebugType>full</DebugType>
25 25 <Optimize>true</Optimize>
26 26 <OutputPath>bin\Release</OutputPath>
27 27 <ErrorReport>prompt</ErrorReport>
28 28 <WarningLevel>4</WarningLevel>
29 29 <ConsolePause>false</ConsolePause>
30 30 </PropertyGroup>
31 31 <ItemGroup>
32 32 <Reference Include="System" />
33 33 </ItemGroup>
34 34 <ItemGroup>
35 35 <Compile Include="Component.cs" />
36 36 <Compile Include="Diagnostics\ConsoleTraceListener.cs" />
37 37 <Compile Include="Diagnostics\EventText.cs" />
38 38 <Compile Include="Diagnostics\IEventTextFormatter.cs" />
39 39 <Compile Include="Diagnostics\LogChannel.cs" />
40 40 <Compile Include="Diagnostics\LogicalOperation.cs" />
41 41 <Compile Include="Diagnostics\TextFileListener.cs" />
42 42 <Compile Include="Diagnostics\TextListenerBase.cs" />
43 43 <Compile Include="Diagnostics\TraceLog.cs" />
44 44 <Compile Include="Diagnostics\TraceContext.cs" />
45 45 <Compile Include="Diagnostics\TraceEvent.cs" />
46 46 <Compile Include="Diagnostics\TraceEventType.cs" />
47 47 <Compile Include="Disposable.cs" />
48 48 <Compile Include="ICancellable.cs" />
49 49 <Compile Include="IProgressHandler.cs" />
50 50 <Compile Include="IProgressNotifier.cs" />
51 51 <Compile Include="IPromise.cs" />
52 52 <Compile Include="IPromiseBase.cs" />
53 53 <Compile Include="IServiceLocator.cs" />
54 54 <Compile Include="ITaskController.cs" />
55 <Compile Include="ManagedPromise.cs" />
56 55 <Compile Include="Parallels\DispatchPool.cs" />
57 56 <Compile Include="Parallels\ArrayTraits.cs" />
58 57 <Compile Include="Parallels\MTQueue.cs" />
59 58 <Compile Include="Parallels\WorkerPool.cs" />
60 59 <Compile Include="ServiceLocator.cs" />
61 60 <Compile Include="TaskController.cs" />
62 61 <Compile Include="ProgressInitEventArgs.cs" />
63 62 <Compile Include="Properties\AssemblyInfo.cs" />
64 63 <Compile Include="Promise.cs" />
65 64 <Compile Include="Parallels\AsyncPool.cs" />
66 65 <Compile Include="Safe.cs" />
67 66 <Compile Include="ValueEventArgs.cs" />
68 67 </ItemGroup>
69 68 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
70 69 <ItemGroup />
71 70 </Project> No newline at end of file
@@ -1,191 +1,191
1 1 using Implab.Diagnostics;
2 2 using System;
3 3 using System.Collections.Generic;
4 4 using System.Diagnostics;
5 5 using System.Linq;
6 6 using System.Text;
7 7 using System.Threading;
8 8
9 9 namespace Implab.Parallels {
10 10 public static class ArrayTraits {
11 11 class ArrayIterator<TSrc> : DispatchPool<int> {
12 12 readonly Action<TSrc> m_action;
13 13 readonly TSrc[] m_source;
14 14 readonly Promise<int> m_promise = new Promise<int>();
15 15 readonly TraceContext m_traceContext;
16 16
17 17 int m_pending;
18 18 int m_next;
19 19
20 20 public ArrayIterator(TSrc[] source, Action<TSrc> action, int threads)
21 21 : base(threads) {
22 22
23 23 Debug.Assert(source != null);
24 24 Debug.Assert(action != null);
25 25
26 26 m_traceContext = TraceContext.Snapshot();
27 27 m_next = 0;
28 28 m_source = source;
29 29 m_pending = source.Length;
30 30 m_action = action;
31 31
32 32 m_promise.Anyway(() => Dispose());
33 33 m_promise.Cancelled(() => Dispose());
34 34
35 35 InitPool();
36 36 }
37 37
38 38 public Promise<int> Promise {
39 39 get {
40 40 return m_promise;
41 41 }
42 42 }
43 43
44 44 protected override void Worker() {
45 TraceContext.Transfer(m_traceContext);
45 TraceContext.Fork(m_traceContext);
46 46 base.Worker();
47 47 }
48 48
49 49 protected override bool TryDequeue(out int unit) {
50 50 unit = Interlocked.Increment(ref m_next) - 1;
51 51 return unit >= m_source.Length ? false : true;
52 52 }
53 53
54 54 protected override void InvokeUnit(int unit) {
55 55 try {
56 56 m_action(m_source[unit]);
57 57 var pending = Interlocked.Decrement(ref m_pending);
58 58 if (pending == 0)
59 59 m_promise.Resolve(m_source.Length);
60 60 } catch (Exception e) {
61 61 m_promise.Reject(e);
62 62 }
63 63 }
64 64 }
65 65
66 66 class ArrayMapper<TSrc, TDst>: DispatchPool<int> {
67 67 readonly Func<TSrc, TDst> m_transform;
68 68 readonly TSrc[] m_source;
69 69 readonly TDst[] m_dest;
70 70 readonly Promise<TDst[]> m_promise = new Promise<TDst[]>();
71 71 readonly TraceContext m_traceContext;
72 72
73 73 int m_pending;
74 74 int m_next;
75 75
76 76 public ArrayMapper(TSrc[] source, Func<TSrc, TDst> transform, int threads)
77 77 : base(threads) {
78 78
79 79 Debug.Assert (source != null);
80 80 Debug.Assert( transform != null);
81 81
82 82 m_next = 0;
83 83 m_source = source;
84 84 m_dest = new TDst[source.Length];
85 85 m_pending = source.Length;
86 86 m_transform = transform;
87 87 m_traceContext = TraceContext.Snapshot();
88 88
89 89 m_promise.Anyway(() => Dispose());
90 90 m_promise.Cancelled(() => Dispose());
91 91
92 92 InitPool();
93 93 }
94 94
95 95 public Promise<TDst[]> Promise {
96 96 get {
97 97 return m_promise;
98 98 }
99 99 }
100 100
101 101 protected override void Worker() {
102 TraceContext.Transfer(m_traceContext);
102 TraceContext.Fork(m_traceContext);
103 103 base.Worker();
104 104 }
105 105
106 106 protected override bool TryDequeue(out int unit) {
107 107 unit = Interlocked.Increment(ref m_next) - 1;
108 108 return unit >= m_source.Length ? false : true;
109 109 }
110 110
111 111 protected override void InvokeUnit(int unit) {
112 112 try {
113 113 m_dest[unit] = m_transform(m_source[unit]);
114 114 var pending = Interlocked.Decrement(ref m_pending);
115 115 if (pending == 0)
116 116 m_promise.Resolve(m_dest);
117 117 } catch (Exception e) {
118 118 m_promise.Reject(e);
119 119 }
120 120 }
121 121 }
122 122
123 123 public static IPromise<TDst[]> ParallelMap<TSrc, TDst> (this TSrc[] source, Func<TSrc,TDst> transform, int threads) {
124 124 if (source == null)
125 125 throw new ArgumentNullException("source");
126 126 if (transform == null)
127 127 throw new ArgumentNullException("transform");
128 128
129 129 var mapper = new ArrayMapper<TSrc, TDst>(source, transform, threads);
130 130 return mapper.Promise;
131 131 }
132 132
133 133 public static IPromise<int> ParallelForEach<TSrc>(this TSrc[] source, Action<TSrc> action, int threads) {
134 134 if (source == null)
135 135 throw new ArgumentNullException("source");
136 136 if (action == null)
137 137 throw new ArgumentNullException("action");
138 138
139 139 var iter = new ArrayIterator<TSrc>(source, action, threads);
140 140 return iter.Promise;
141 141 }
142 142
143 143 public static IPromise<TDst[]> ChainedMap<TSrc, TDst>(this TSrc[] source, ChainedOperation<TSrc, TDst> transform, int threads) {
144 144 if (source == null)
145 145 throw new ArgumentNullException("source");
146 146 if (transform == null)
147 147 throw new ArgumentNullException("transform");
148 148 if (threads <= 0)
149 149 throw new ArgumentOutOfRangeException("Threads number must be greater then zero");
150 150
151 151 if (source.Length == 0)
152 152 return Promise<TDst[]>.ResultToPromise(new TDst[0]);
153 153
154 154 var promise = new Promise<TDst[]>();
155 155 var res = new TDst[source.Length];
156 156 var pending = source.Length;
157 157
158 158 var semaphore = new Semaphore(threads, threads);
159 159
160 160 AsyncPool.InvokeNewThread(() => {
161 161 for (int i = 0; i < source.Length; i++) {
162 162 if(promise.IsResolved)
163 163 break; // stop processing in case of error or cancellation
164 164 var idx = i;
165 165 semaphore.WaitOne();
166 166 try {
167 167 var p1 = transform(source[i]);
168 168 p1.Anyway(() => semaphore.Release());
169 169 p1.Cancelled(() => semaphore.Release());
170 170 p1.Then(
171 171 x => {
172 172 res[idx] = x;
173 173 var left = Interlocked.Decrement(ref pending);
174 174 if (left == 0)
175 175 promise.Resolve(res);
176 176 },
177 177 e => promise.Reject(e)
178 178 );
179 179
180 180 } catch (Exception e) {
181 181 promise.Reject(e);
182 182 }
183 183 }
184 184 return 0;
185 185 });
186 186
187 187 return promise.Anyway(() => semaphore.Dispose());
188 188 }
189 189
190 190 }
191 191 }
@@ -1,50 +1,71
1 1 using Implab.Diagnostics;
2 2 using System;
3 3 using System.Threading;
4 4
5 5 namespace Implab.Parallels {
6 6 /// <summary>
7 7 /// Класс для распаралеливания задач.
8 8 /// </summary>
9 9 /// <remarks>
10 10 /// Используя данный класс и лямда выражения можно распараллелить
11 11 /// вычисления, для этого используется концепция обещаний.
12 12 /// </remarks>
13 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 16 var p = new Promise<T>();
17 17 var caller = TraceContext.Snapshot();
18 18
19 19 ThreadPool.QueueUserWorkItem(param => {
20 TraceContext.Transfer(caller);
20 TraceContext.Fork(caller);
21 21 try {
22 22 p.Resolve(func());
23 23 } catch(Exception e) {
24 24 p.Reject(e);
25 25 }
26 26 });
27 27
28 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 32 var p = new Promise<T>();
33 33
34 34 var caller = TraceContext.Snapshot();
35 35
36 36 var worker = new Thread(() => {
37 TraceContext.Transfer(caller);
37 TraceContext.Fork(caller);
38 38 try {
39 39 p.Resolve(func());
40 40 } catch (Exception e) {
41 41 p.Reject(e);
42 42 }
43 43 });
44 44 worker.IsBackground = true;
45 45 worker.Start();
46 46
47 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
General Comments 0
You need to be logged in to leave comments. Login now