同步方法
多线程开发的时候,开发者经常会遇到在一个方法里锁定和释放一个对象的情景,本文演示了如何使用MethodImpl属性标识一个需要同步的方法,让编译器自动产生同步代码。
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
public class MyClass
{
[System.Runtime.CompilerServices.MethodImpl(
System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
public void SetCounter(int counter)
{
this.Counter = counter;
}
[System.Runtime.CompilerServices.MethodImpl(
System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
public int GetCounter()
{
return this.Counter;
}
protected string m_CountingString;
protected int Counter
{
set
{
m_CountingString = "";
m_CountingString = value.ToString();
}
get
{
return Convert.ToInt32(m_CountingString);
}
}
public MyClass()
{
m_CountingString = "0";
}
}
public class MyForm : System.Windows.Forms.Form
{
public static void Main()
{
try
{
Application.Run(new MyForm());
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
Console.ReadLine();
}
}
private Button m_CreateThreads;
private Label m_CounterLabel;
protected MyClass m_MyClass;
public MyForm()
{
this.m_CreateThreads = new System.Windows.Forms.Button();
this.m_CreateThreads.Location = new System.Drawing.Point(32, 32);
this.m_CreateThreads.Name = "CreateThreads";
this.m_CreateThreads.Size = new System.Drawing.Size(112, 23);
this.m_CreateThreads.TabIndex = 0;
this.m_CreateThreads.Text = "Create Threads";
this.m_CreateThreads.Click += new System.EventHandler(this.OnCreateThreads);
this.m_CounterLabel = new System.Windows.Forms.Label();
this.m_CounterLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.m_CounterLabel.ForeColor = System.Drawing.Color.Red;
this.m_CounterLabel.Location = new System.Drawing.Point(32, 80);
this.m_CounterLabel.Name = "m_CounterLabel";
this.m_CounterLabel.Size = new System.Drawing.Size(128, 64);
this.m_CounterLabel.TabIndex = 1;
this.m_CounterLabel.Text = "0";
this.ClientSize = new System.Drawing.Size(248, 165);
this.Controls.AddRange(new System.Windows.Forms.Control[]
{
this.m_CreateThreads,
this.m_CounterLabel
});
this.Text = "SynchMethod";
m_MyClass = new MyClass();
m_CounterLabel.Text = m_MyClass.GetCounter().ToString();
}
private void OnCreateThreads(object sender,EventArgs e)
{
ThreadStart threadStart1 = new ThreadStart(IncrementCounter);
Thread thread1 = new Thread(threadStart1);
thread1.IsBackground = true;
thread1.Start();
ThreadStart threadStart2 = new ThreadStart(UpdateCounter);
Thread thread2 = new Thread(threadStart2);
thread2.IsBackground = true;
thread2.Start();
}
private void ChangeLabel()
{
if (InvokeRequired)
{
this.Invoke(new MethodInvoker(ChangeLabel));
return;
}
this.m_CounterLabel.Text = m_MyClass.GetCounter().ToString();
}
protected void IncrementCounter()
{
while(true)
{
int counter = m_MyClass.GetCounter();
counter++;
Console.WriteLine("IncrementCounter:{0}", counter);
m_MyClass.SetCounter(counter);
Thread.Sleep(300);
}
}
protected void UpdateCounter()
{
while(true)
{
Console.WriteLine("UpdateCounter");
this.ChangeLabel();
Thread.Sleep(300);
}
}
}
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
public class MyClass
{
[System.Runtime.CompilerServices.MethodImpl(
System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
public void SetCounter(int counter)
{
this.Counter = counter;
}
[System.Runtime.CompilerServices.MethodImpl(
System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
public int GetCounter()
{
return this.Counter;
}
protected string m_CountingString;
protected int Counter
{
set
{
m_CountingString = "";
m_CountingString = value.ToString();
}
get
{
return Convert.ToInt32(m_CountingString);
}
}
public MyClass()
{
m_CountingString = "0";
}
}
public class MyForm : System.Windows.Forms.Form
{
public static void Main()
{
try
{
Application.Run(new MyForm());
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
Console.ReadLine();
}
}
private Button m_CreateThreads;
private Label m_CounterLabel;
protected MyClass m_MyClass;
public MyForm()
{
this.m_CreateThreads = new System.Windows.Forms.Button();
this.m_CreateThreads.Location = new System.Drawing.Point(32, 32);
this.m_CreateThreads.Name = "CreateThreads";
this.m_CreateThreads.Size = new System.Drawing.Size(112, 23);
this.m_CreateThreads.TabIndex = 0;
this.m_CreateThreads.Text = "Create Threads";
this.m_CreateThreads.Click += new System.EventHandler(this.OnCreateThreads);
this.m_CounterLabel = new System.Windows.Forms.Label();
this.m_CounterLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.m_CounterLabel.ForeColor = System.Drawing.Color.Red;
this.m_CounterLabel.Location = new System.Drawing.Point(32, 80);
this.m_CounterLabel.Name = "m_CounterLabel";
this.m_CounterLabel.Size = new System.Drawing.Size(128, 64);
this.m_CounterLabel.TabIndex = 1;
this.m_CounterLabel.Text = "0";
this.ClientSize = new System.Drawing.Size(248, 165);
this.Controls.AddRange(new System.Windows.Forms.Control[]
{
this.m_CreateThreads,
this.m_CounterLabel
});
this.Text = "SynchMethod";
m_MyClass = new MyClass();
m_CounterLabel.Text = m_MyClass.GetCounter().ToString();
}
private void OnCreateThreads(object sender,EventArgs e)
{
ThreadStart threadStart1 = new ThreadStart(IncrementCounter);
Thread thread1 = new Thread(threadStart1);
thread1.IsBackground = true;
thread1.Start();
ThreadStart threadStart2 = new ThreadStart(UpdateCounter);
Thread thread2 = new Thread(threadStart2);
thread2.IsBackground = true;
thread2.Start();
}
private void ChangeLabel()
{
if (InvokeRequired)
{
this.Invoke(new MethodInvoker(ChangeLabel));
return;
}
this.m_CounterLabel.Text = m_MyClass.GetCounter().ToString();
}
protected void IncrementCounter()
{
while(true)
{
int counter = m_MyClass.GetCounter();
counter++;
Console.WriteLine("IncrementCounter:{0}", counter);
m_MyClass.SetCounter(counter);
Thread.Sleep(300);
}
}
protected void UpdateCounter()
{
while(true)
{
Console.WriteLine("UpdateCounter");
this.ChangeLabel();
Thread.Sleep(300);
}
}
}
我们使用ildasm看看编译器对MyClass.GetCounter方法产生的代码:
.method public hidebysig instance int32 GetCounter() cil managed synchronized
{
// 代码大小 12 (0xc)
.maxstack 1
.locals init ([0] int32 CS$1$0000)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: call instance int32 MyClass::get_Counter()
IL_0007: stloc.0
IL_0008: br.s IL_000a
IL_000a: ldloc.0
IL_000b: ret
} // end of method MyClass::GetCounter
{
// 代码大小 12 (0xc)
.maxstack 1
.locals init ([0] int32 CS$1$0000)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: call instance int32 MyClass::get_Counter()
IL_0007: stloc.0
IL_0008: br.s IL_000a
IL_000a: ldloc.0
IL_000b: ret
} // end of method MyClass::GetCounter