我汇总了一下关于C#多线程的使用方法,包括一些简单的锁和线程池的常用方法,虽然古老了一些,但是在一些老的项目中还是能经常用到的,多线程和异步有点儿小区别,分两篇文章来汇总,下一篇我再总结一下关于C#异步的新旧使用方法。
Thread thread0 = Thread.CurrentThread;
thread0.Name = "Main Thread";
string threadMessage = string.Format("Thread ID:{0}\n Current AppDomainId:{1}\n " +
"Current ContextId:{2}\n Thread Name:{3}\n" +
"Thread State:{4}\n Thread Priority:{5}\n",
thread0.ManagedThreadId, Thread.GetDomainID(), Thread.CurrentContext.ContextID,thread0.Name, thread0.ThreadState, thread0.Priority);
Console.WriteLine(threadMessage);
// 无参数线程
Thread thread1 = new Thread(new ThreadStart(ShowMessage));
thread1.Start();
// 有参数线程
// 有参数委托线程
//Thread thread2 = new Thread(new ParameterizedThreadStart(ShowMessage));
Thread thread2 = new Thread(ShowMessage1);
Person person = new Person();
person.Name = "Jack";
person.Age = 21;
thread2.Start(person);
//构造有参数线程类
MyThread myThread = new MyThread("hello world");
Thread thread = new Thread(myThread.ThreadMain);
thread.Start();
public static void ShowMessage()
{
string message = string.Format("Async threadId is :{0}", Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(message);
for (int n = 0; n < 10; n++)
{
Thread.Sleep(300);
Console.WriteLine("The number is:" + n.ToString());
}
}
// 构造有参数线程类
public class MyThread
{
private string data;
public MyThread(string data)
{
this.data = data;
}
public void ThreadMain()
{
Console.WriteLine("Running in a thread,data: {0}", data);
}
}
public class Person
{
public string Name {
get; set; }
public int Age {
get; set; }
}
public static void ShowMessage(object _person)
{
if (_person != null)
{
Person person = (Person)_person;
string message = string.Format("\n{0}'s age is {1}!\nAsync threadId is:{2}", person.Name, person.Age, Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(message);
}
for (int n = 0; n < 10; n++)
{
Thread.Sleep(300);
Console.WriteLine("The number is:" + n.ToString());
}
}
为同步访问变量,使用了一个C#语言的关键字Lock,它可以把一段代码定义为互斥段,互斥段在一个时刻内只允许一个线程进入执行,实际上是Monitor.Enter(obj),Monitor.Exit(obj)的语法糖。
obj代表你希望锁定的对象,注意一下几点:
BookShop book = new BookShop();
Thread t1 = new Thread(book.Sale);
Thread t2 = new Thread(book.Sale);
t1.Start();
t2.Start();
class BookShop
{
//剩余图书数量
public int num = 1;
private static readonly object locker = new object();
public void Sale()
{
lock (locker)
{
int tmp = num;
if (tmp > 0)//判断是否有书,如果有就可以卖
{
Thread.Sleep(1000);
num -= 1;
Console.WriteLine("售出一本图书,还剩余{0}本", num);
}
else
{
Console.WriteLine("没有了");
}
}
}
}
CLR线程池分为工作者线程(workerThreads)与I/O线程 (completionPortThreads) 两种,工作者线程是主要用作管理CLR内部对象的运作,I/O(Input/Output) 线程顾名思义是用于与外部系统交换信息。
通过
两个方法可以分别读取和设置CLR线程池中工作者线程与I/O线程的最大线程数。
在Framework2.0中最大线程默认为25CPU数,在Framewok3.0、4.0中最大线程数默认为250CPU数,在近年 I3,I5,I7 CPU出现后,线程池的最大值一般默认为1000、2000。若想测试线程池中有多少的线程正在投入使用,可以通过ThreadPool.GetAvailableThreads( out int workerThreads,out int completionPortThreads ) 方法。
使用CLR线程池的工作者线程一般有两种方式,一是直接通过 ThreadPool.QueueUserWorkItem() 方法,二是通过委托。
// 通过QueueUserWorkItem启动工作者线程
// 把CLR线程池的最大值设置为1000
ThreadPool.SetMaxThreads(1000, 1000);
// 显示主线程启动时线程池信息
ThreadMessage("Start");
// 启动工作者线程
ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncCallback1));
ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncCallback2), "Hello Elva");
for (int i = 1; i <= 10; i++)
{
//ThreadPool执行任务
ThreadPool.QueueUserWorkItem(
new WaitCallback(
(obj) =>
{
Console.WriteLine($"第{obj}个执行任务");
}
),
i);
}
static void AsyncCallback1(object state)
{
Thread.Sleep(200);
ThreadMessage("AsyncCallback");
Console.WriteLine("Async thread do work!");
}
static void AsyncCallback2(object state)
{
Thread.Sleep(200);
ThreadMessage("AsyncCallback");
string data = (string)state;
Console.WriteLine("Async thread do work!\n" + data);
}
//显示线程现状
static void ThreadMessage(string data)
{
string message = string.Format("{0}\n CurrentThreadId is {1}",data, Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(message);
}
使用Thread.Start()启动的线程默认为前台线程,而系统必须等待所有前台线程运行结束后,
应用程序域才会自动卸载。线程Thread有一个属性IsBackground,通过把此属性设置为true,
就可以把线程设置为后台线程!这时应用程序域将在主线程完成时就被卸载,而不会等待异步线程的运行。
Thread thread3 = new Thread(new ThreadStart(ShowMessage));
thread3.IsBackground = true;
thread3.Start();
Thread thread4 = new Thread(new ThreadStart(AsyncThread));
thread4.IsBackground = true;
thread4.Start();
//阻塞主线程
thread4.Join();
public partial class MainForm : Form
{
Thread thread;
int index = 0;
public MainForm()
{
InitializeComponent();
}
//启动按钮
private void startBtn_Click(object sender, EventArgs e)
{
//创建一个线程,每秒在textbox中追加一下执行次数
if (thread==null)
{
thread = new Thread(() =>
{
while (true)
{
index++;
try
{
Thread.Sleep(1000);
textBox1.Invoke(new Action(() =>
{
textBox1.AppendText($"第{index}次,");
}));
}
catch (Exception ex) {
MessageBox.Show(ex.ToString()); }
}
});
//启动线程
thread.Start();
}
}
//挂起按钮
private void suspendBtn_Click(object sender, EventArgs e)
{
if (thread != null && thread.ThreadState==ThreadState.Running || thread.ThreadState==ThreadState.WaitSleepJoin)
{
thread.Suspend();
}
}
//继续运行挂起的线程
private void ResumeBtn_Click(object sender, EventArgs e)
{
if (thread!=null && thread.ThreadState==ThreadState.Suspended)
{
thread.Resume();
}
}
//interrupt会报一个异常,并中断处于WaitSleepJoin状态的线程
private void InterruptBtn_Click(object sender, EventArgs e)
{
if (thread != null && thread.ThreadState==ThreadState.WaitSleepJoin)
{
thread.Interrupt();
}
}
//abort会报一个异常,并销毁线程
private void AbortBtn_Click(object sender, EventArgs e)
{
if (thread != null)
{
thread.Abort();
}
}
//定时器,刷新显示线程状态
private void timer1_Tick(object sender, EventArgs e)
{
if (thread!=null)
{
txtStatus.Text = thread.ThreadState.ToString();
}
}
//窗体加载
private void Form1_Load(object sender, EventArgs e)
{
timer1.Interval = 100;
timer1.Enabled = true;
}
//窗口关闭时,关闭进程
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
System.Diagnostics.Process[] processes =
System.Diagnostics.Process.GetProcessesByName("ThreadForm");
foreach (var item in processes)
{
item.Kill();
}
}
}