使用 lock 取代 MethodImplOptions.Synchronized
情境:
ASP.NET 的網站忽然某一個功能會出現 System.Threading.SynchronizationLockException 其它都是正常.
錯誤訊息:
System.Threading.SynchronizationLockException: Object synchronization method was called from an unsynchronized block of code.
測試:
測試發現如果使用MethodImplOptions.Synchronized,若thread進入執行並故意abort掉,可以重現.SynchronizationLockException。
若改用lock則不會發生問題
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Runtime.CompilerServices;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace LockDemo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Thread t1 = new Thread(MyLib.Run);
t1.Start();
Thread t2 = new Thread(MyLib.Run2);
t2.Start();
Thread t3 = new Thread(MyLib.Run3);
t3.Start();
Thread t4 = new Thread(MyLib.Run4);
t4.Start();
}
}
public class MyLib
{
public static int intCount = 0;
[MethodImpl(MethodImplOptions.Synchronized)]
public static void Run()
{
System.Threading.Thread.Sleep(5000);
intCount++;
MessageBox.Show(String.Format("RUN1:Thread ID {0}:{1}",
System.Threading.Thread.CurrentThread.ManagedThreadId.ToString(),
MyLib.intCount.ToString()
));
}
[MethodImpl(MethodImplOptions.Synchronized)]
public static void Run2()
{
System.Threading.Thread.Sleep(5000);
intCount++;
MessageBox.Show(String.Format("RUN2:Thread ID {0}:{1}",
System.Threading.Thread.CurrentThread.ManagedThreadId.ToString(),
MyLib.intCount.ToString()
));
}
public static void Run3()
{
System.Threading.Thread.Sleep(5000);
intCount++;
MessageBox.Show(String.Format("RUN3:Thread ID {0}:{1}",
System.Threading.Thread.CurrentThread.ManagedThreadId.ToString(),
MyLib.intCount.ToString()
));
}
public static void Run4()
{
System.Threading.Thread.Sleep(5000);
intCount++;
MessageBox.Show(String.Format("RUN4:Thread ID {0}:{1}",
System.Threading.Thread.CurrentThread.ManagedThreadId.ToString(),
MyLib.intCount.ToString()
));
}
}
}
Enjoy. Jacky