詳解C#如何解決程序卡頓的問題(多線程初步學(xué)習)
正文
不帶參數(shù)的多線程實現(xiàn)
第一步 建立控制臺應(yīng)用

第二步 引用System.Threading.Thread
using System.Threading;
在 C# 中,System.Threading.Thread 類用于線程的工作。它允許創(chuàng)建并訪問多線程應(yīng)用程序中的單個線程。進程中第一個被執(zhí)行的線程稱為主線程。
第三步:完成代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace 多線程Test
{
class Program
{
static void Main(string[] args)
{
int num = 100;
for (int i = 0; i < num; i++)
{
//無參的多線程
noParmaThread();
}
}
private static void StartThread()
{
Console.WriteLine("------開始了新線程------");
Thread.Sleep(2000);//wait
Console.WriteLine("------線程結(jié)束------");
}
/// <summary>
///不需要傳遞參數(shù)
/// </summary>
private static void noParmaThread()
{
ThreadStart threadStart = new ThreadStart(StartThread);
var thread = new Thread(threadStart);
thread.Start();//開始線程
}
}
}
運行結(jié)果

拓展:C#多線程刷新界面卡死測試
背景
在上位機程序開發(fā)過程中,不可避免的會用到多線程,如處理Socket通信、PLC讀取、界面數(shù)據(jù)實時刷新等。在某個項目中由于開啟的線程很多,出現(xiàn)了不定期界面卡死狀況,但后臺線程還在運行,日志還在輸出。為了解決這個問題,特寫了模擬程序進行問題復(fù)現(xiàn)。順便把過程分享一下。
要點
1、區(qū)分Control.BeginInvoke和Control.Invoke的用法
2、區(qū)分System.Timers.Timer、System.Threading.ThreadPool、System.Threading.Thread
Demo
創(chuàng)建一個WinForm應(yīng)用程序,把工程屬性的輸出類型設(shè)置為控制臺應(yīng)用程序,方便運行時查看日志。
關(guān)鍵代碼
BasicInvoker
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WinApp
{
/// <summary>
/// 調(diào)用器
/// </summary>
public class BasicInvoker
{
public delegate void Invoke();
private Form form = null;
private TextBox txt = null;
private object value = String.Empty;
public BasicInvoker(Form form, TextBox txt, object value)
{
this.form = form;
this.txt = txt;
this.value = value;
}
public void SetValue()
{
if (this.form != null && !this.form.IsDisposed)
{
if (this.form.InvokeRequired)
{
Delegate d = new Invoke(this.DoWork);
try
{
this.form.Invoke(d, null);
//this.form.BeginInvoke(d);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
else
{
this.DoWork();
}
}
}
public void DoWork()
{
if (this.txt != null)
{
this.txt.Text = this.value.ToString();
Console.WriteLine(String.Format("{0:yyyy-MM-dd HH:mm:ss.fff}", DateTime.Now) + " " + this.value.ToString() + "...1");
System.Threading.Thread.Sleep(200);
Console.WriteLine(String.Format("{0:yyyy-MM-dd HH:mm:ss.fff}", DateTime.Now) + " " + this.value.ToString() + "...2");
}
}
}
}
FrmTest
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WinApp
{
public partial class FrmTester : Form
{
#region 變量定義
private System.Timers.Timer timer1 = null;
private System.Timers.Timer timer2 = null;
private System.Timers.Timer timer3 = null;
private System.Threading.Thread thread1 = null;
private System.Threading.Thread thread2 = null;
private System.Threading.Thread thread3 = null;
#endregion
#region 構(gòu)造方法
public FrmTester()
{
InitializeComponent();
}
#endregion
#region 事件處理
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
if (timer1 == null)
{
timer1 = new System.Timers.Timer();
timer1.Interval = 500;
timer1.Elapsed += t1_Elapsed;
timer1.Start();
}
}
private void button2_Click(object sender, EventArgs e)
{
if (timer2 == null)
{
timer2 = new System.Timers.Timer();
timer2.Interval = 500;
timer2.Elapsed += t2_Elapsed;
timer2.Start();
}
}
private void button3_Click(object sender, EventArgs e)
{
if (timer3 == null)
{
timer3 = new System.Timers.Timer();
timer3.Interval = 500;
timer3.Elapsed += t3_Elapsed;
timer3.Start();
}
}
private void button4_Click(object sender, EventArgs e)
{
System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(this.CallBack1));
}
private void button5_Click(object sender, EventArgs e)
{
System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(this.CallBack2));
}
private void button6_Click(object sender, EventArgs e)
{
System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(this.CallBack3));
}
private void button7_Click(object sender, EventArgs e)
{
if (this.thread1 == null)
{
this.thread1 = new System.Threading.Thread(new System.Threading.ThreadStart(this.CallBack1));
this.thread1.Start();
}
}
private void button8_Click(object sender, EventArgs e)
{
if (this.thread2 == null)
{
this.thread2 = new System.Threading.Thread(new System.Threading.ThreadStart(this.CallBack2));
this.thread2.Start();
}
}
private void button9_Click(object sender, EventArgs e)
{
if (this.thread3 == null)
{
this.thread3 = new System.Threading.Thread(new System.Threading.ThreadStart(this.CallBack3));
this.thread3.Start();
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Console.WriteLine("FormClosing...");
if (this.timer1 != null)
{
this.timer1.Stop();
this.timer1.Dispose();
}
if (this.timer2 != null)
{
this.timer2.Stop();
this.timer2.Dispose();
}
if (this.timer3 != null)
{
this.timer3.Stop();
this.timer3.Dispose();
}
if (this.thread1 != null)
{
//if (this.thread1.ThreadState == System.Threading.ThreadState.Running)
{
this.thread1.Abort();
}
}
if (this.thread2 != null)
{
//if (this.thread2.ThreadState == System.Threading.ThreadState.Running)
{
this.thread2.Abort();
}
}
if (this.thread3 != null)
{
//if (this.thread3.ThreadState == System.Threading.ThreadState.Running)
{
this.thread3.Abort();
}
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
Console.WriteLine("FormClosed...");
}
#endregion
#region 定時處理方法定義
private void t1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//lock(Global.PublicVar.Instance.Locker1)
lock (String.Empty)
{
BasicInvoker invoker = new BasicInvoker(this, this.textBox1, Guid.NewGuid().ToString());
invoker.SetValue();
}
}
private void t2_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
lock (Global.PublicVar.Instance.Locker1)
lock (String.Empty)
{
BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
invoker.SetValue();
}
}
private void t3_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//lock (Global.PublicVar.Instance.Locker1)
lock (String.Empty)
{
BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
invoker.SetValue();
}
}
public void CallBack1(object state)
{
while(true)
{
//lock (Global.PublicVar.Instance.Locker1)
lock(String.Empty)
{
BasicInvoker invoker = new BasicInvoker(this, this.textBox1, Guid.NewGuid().ToString());
invoker.SetValue();
}
System.Threading.Thread.Sleep(500);
}
}
public void CallBack2(object state)
{
while (true)
{
//lock (Global.PublicVar.Instance.Locker1)
lock(String.Empty)
{
BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
invoker.SetValue();
}
System.Threading.Thread.Sleep(500);
}
}
public void CallBack3(object state)
{
while (true)
{
//lock (Global.PublicVar.Instance.Locker1)
lock(String.Empty)
{
BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
invoker.SetValue();
}
System.Threading.Thread.Sleep(500);
}
}
public void CallBack1()
{
while (true)
{
//lock (Global.PublicVar.Instance.Locker1)
lock (String.Empty)
{
BasicInvoker invoker = new BasicInvoker(this, this.textBox1, Guid.NewGuid().ToString());
invoker.SetValue();
}
System.Threading.Thread.Sleep(500);
}
}
public void CallBack2()
{
while (true)
{
//lock (Global.PublicVar.Instance.Locker1)
lock (String.Empty)
{
BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
invoker.SetValue();
}
System.Threading.Thread.Sleep(500);
}
}
public void CallBack3()
{
while (true)
{
//lock (Global.PublicVar.Instance.Locker1)
lock (String.Empty)
{
BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
invoker.SetValue();
}
System.Threading.Thread.Sleep(500);
}
}
#endregion
}
}
運行圖:


運行結(jié)果:
一、使用Control.BeginInvoke的情況
public void SetValue()
{
if (this.form != null && !this.form.IsDisposed)
{
if (this.form.InvokeRequired)
{
Delegate d = new Invoke(this.DoWork);
try
{
//this.form.Invoke(d, null);
this.form.BeginInvoke(d);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
else
{
this.DoWork();
}
}
}
1.1、System.Timers.Timer開啟2以上很快界面卡死,日志正常輸出。
1.2、System.Threading.ThreadPool開啟3個時,運行一會界面卡死,日志正常輸出。
1.3、System.Threading.Thread開啟3個時,運行一會界面卡死,日志正常輸出。
二、使用Control.Invoke的情況
public void SetValue()
{
if (this.form != null && !this.form.IsDisposed)
{
if (this.form.InvokeRequired)
{
Delegate d = new Invoke(this.DoWork);
try
{
this.form.Invoke(d, null);
//this.form.BeginInvoke(d);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
else
{
this.DoWork();
}
}
}
2.1、System.Timers.Timer開啟3個時很快界面卡死,日志正常輸出。
2.2、System.Threading.ThreadPool開啟3個時,界面正常操作,日志正常輸出。
2.3、System.Threading.Thread開啟3個時,界面正常操作,日志正常輸出。
測試總結(jié):
1、System.Threading.ThreadPool與System.Threading.Thread運行效果基本相同。
2、在多線程刷新界面時盡量通過Control.Invoke調(diào)用委托實現(xiàn)。
小結(jié)
到此這篇關(guān)于詳解C#如何解決程序卡頓的問題(多線程初步學(xué)習)的文章就介紹到這了,更多相關(guān)C#解決程序卡頓內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解C#中對于接口的實現(xiàn)方式(隱式接口和顯式接口)
這篇文章主要介紹了詳解C#中對于接口的實現(xiàn)方式(隱式接口和顯式接口),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2019-12-12
c# Winform同一數(shù)據(jù)源多個控件保持同步
通過對控件屬性設(shè)置數(shù)據(jù)源綁定,利用Windows數(shù)據(jù)更改通知這一特性,只要訂閱(設(shè)定綁定)的控件都能接收到數(shù)據(jù)的變化通知。 通過DataBindings方法實現(xiàn)雙向數(shù)據(jù)綁定2021-06-06

