概要: このビデオでは、スレッドの基本概念から、マルチスレッドについて非常に徹底的に説明しています -> .net のさまざまなバージョンで使用されるスレッド化メソッド -> マルチスレッドに関する一般的な問題 -> Shuangseqiu プロジェクトの実践、すべての知識ポイントにはコードの実践が含まれています。あなたはそれから恩恵を受けるでしょう 非常に浅いです。学習メモと実践的なコードが添付されています。
ビデオ
目次
- 1. スレッドとプロセスの概念とその利点と欠点
- 2. 4つの非同期待機方法
- 3. .net1.0基本バージョンのスレッドオブジェクト
- 4. ネット 2.0 スレッドプール
- 5. .net3.0タスク
-
- 1.タスクスレッドの起動
- 2.waitall と waitany はメインスレッドインターフェイスをブロックします。
- 3.task.whenall. continuewith()
- 4.taskfactory. continuewith()
- 5. 最大 11 スレッドのみが動作するように設計されています
- 6. taskfactory は終了したスレッドを検出すると、スレッド ID を返します。
- 7. メインスレッドのブロックを避けるために、タスクを複数回ネストすることができます。
- 8. 2 つの waitall が順番に実行されます。
- 9.thread.sleep() スレッドはスタックしますが、 task.delay() はスレッドをスタックさせません
- 10.タスクスレッド完了識別
- 6. .net4.5パラレル
- 7. スレッドコア
- 8、.net.0 await/async
- 9. ダブルカラーボールプロジェクト
- 10. ナレッジポイントコードの概要
1. スレッドとプロセスの概念とその利点と欠点
スレッド: プログラム実行の最小単位。すべての操作はスレッドによって完了します。同期が使用される場合、リソースは常にこのスレッドによって占有されるため、他のインターフェイスは動作できず、インターフェイスはスタックします。
1. 始まりは制御できない 2. 終わりは制御できない
時間 (i++) とリソース (thread.sleep) を消費するメソッド
2. 4つの非同期待機方法
1. 非同期制御待機コールバックコールバック
アクションの実行後、asyncResult と "nimen" がパラメータとしてコールバックに渡されます。
2. 非同期制御のwaiting-asyncResult.IsCompleted
3. 非同期制御は WaitOne() セマフォを待機します
4. 非同期制御はendinvokeを待ち、非同期関数の戻り値を取得します。
5.ビデオレッスンコード1
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace multithread
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Console.WriteLine($"[------------主线程start: 线程号:({
Thread.CurrentThread.ManagedThreadId.ToString("00")})---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
/*1调用委托
{
Action<string> action = this.dosomething;
action.Invoke("AA");//同步调用委托
action("BB");//同步调用委托
action.BeginInvoke("cc", null, null);//异步调用委托
}
/*2异步-不可控
{
Action<string> action = this.dosomething;
for (int i = 0; i < 5; i++)
{
string name = string.Format($"btn_click_{i}");
action.BeginInvoke(name, null, null);//异步调用委托
}
}*/
/*3.异步不可控
{
Action<string> action = this.dosomething;
action.BeginInvoke("cc", null, null);
Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
}*/
/*4.异步等待1-回调
{
Action<string> action = this.dosomething;
AsyncCallback callback = new AsyncCallback(i => Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]"));
//简单写法
AsyncCallback callback1 = i => Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
action.BeginInvoke("cc", callback, null);
}*/
/*5.异步等待1-回调解析(action执行完将asyncResult、"nimen"当成参数传给callback)-不卡界面
{
Action<string> action = this.dosomething;
IAsyncResult asyncResult = null;
AsyncCallback callback = i =>
{
Console.WriteLine(object.ReferenceEquals(asyncResult , i));
Console.WriteLine(i.AsyncState);
Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
};
asyncResult = action.BeginInvoke("cc", callback, "nimen");
}
*/
/*6.异步等待2 asyncResult.IsCompleted-回调解析-while函数卡界面
{
Action<string> action = this.dosomething;
IAsyncResult asyncResult = null;
AsyncCallback callback = i =>
{
Console.WriteLine(object.ReferenceEquals(asyncResult, i));
Console.WriteLine(i.AsyncState);
Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
};
asyncResult = action.BeginInvoke("cc", callback, "nimen");
int a = 0;
while (!asyncResult.IsCompleted)
{
if (a < 10)
{
Console.WriteLine($"文件上传{a++ * 10}%..");
Console.WriteLine($"线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
}
else
{
Console.WriteLine($"文件上传99.9%..");
}
Thread.Sleep(200);
}
}*/
/*7.异步等待3-WaitOne()-信号量3
{
Action<string> action = this.dosomething;
IAsyncResult asyncResult = action.BeginInvoke("cc", null, null);
Console.WriteLine("dosomething");
Console.WriteLine("dosomething");
asyncResult.AsyncWaitHandle.WaitOne();//等待异步任务完成后,才打印计算完成
asyncResult.AsyncWaitHandle.WaitOne(2000);//限时等待
Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
}*/
/*.8异步等待4endinvoke-拿到委托函数的返回值
{
Action<string> action = this.dosomething;
Func<int> func = () =>
{
Thread.Sleep(2000);
return DateTime.Now.Day;
};
Console.WriteLine($"func.Invoke()={ func.Invoke()}");
IAsyncResult asyncResult=func.BeginInvoke(r =>
{
Console.WriteLine(r.AsyncState);
}, "nimen");
Console.WriteLine($"func.EndInvoke={ func.EndInvoke(asyncResult)}");
Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
}*/
Console.WriteLine($"[------------主线程end: 线程号:({
Thread.CurrentThread.ManagedThreadId.ToString("00")})---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
}
private void dosomething(string name)
{
Console.WriteLine($"[****Dosomething {
name} start: 线程号:({
Thread.CurrentThread.ManagedThreadId.ToString("00")})---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}*******]");
long result = 0;
for(int i =0; i < 10000000; i++)
{
result += i;
}
Thread.Sleep(2000);
Console.WriteLine($"[****Dosomething {
name} end: 线程号:({
Thread.CurrentThread.ManagedThreadId.ToString("00")})---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}{
result}*******]");
}
}
}
3. .net1.0基本バージョンのスレッドオブジェクト
1. スレッドの起動
{
//Action<string> action = this.dosomething;
//IAsyncResult asyncResult = action.BeginInvoke("cc", null, null);
//Action action1 =()=> this.dosomething("CC");
//1.线程启动 thread.Start();
ThreadStart threadStart = () => this.dosomething("cc");
Thread thread = new Thread(threadStart);
thread.Start();
//2.线等待程thread.Join();
thread.Join(500);//卡主线程
Console.WriteLine($"等待500ms");
thread.Join();
while (thread.ThreadState != ThreadState.Stopped)
{
Thread.Sleep(100);//cpu时间片交出去干其他的事,但是内存还是占用
}
2.thread.join()\thread.sleep()\thread.IsBackfround
thread.join(500), 他の人のスレッドは 500 ミリ秒待機しています。この時点で、プロジェクトには 2 つのスレッドがあります。1 つは 500 ミリ秒待機し、もう 1 つは thread.sleep(500) を実行しています
。 CPU タイム スライスを引き渡す独自のスレッド 他のことをするために外出しますが、メモリはまだ占有されています
フォアグラウンド スレッドは 500 ミリ秒スリープします ソフトウェアがクラッシュすると、ログが吐き出されます
4. ネット 2.0 スレッドプール
1. スレッドの起動とスレッド プール内のスレッドの最大数の設定
2.manualResetEvent.WaitOne() 非同期制御待機
{
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(t =>
{
this.dosomething("cc");
manualResetEvent.Set();
});//接收一个没有返回值的委托
manualResetEvent.WaitOne();
Console.WriteLine($"等待ThreadPool.QueueUserWorkItem执行完再执行");
}
waitone() のリスクは、使用可能なスレッドがない場合にスタックしてしまうことです。
3. 手書きの非同期コールバック関数
4. 戻り値付きのデリゲート非同期呼び出し (フランス語の構造を学習)
5. .net3.0タスク
1.タスクスレッドの起動
2.waitall と waitany はメインスレッドインターフェイスをブロックします。
waitall、waitany アプリケーション シナリオ
3.task.whenall. continuewith()
まず、task.whenall はメイン インターフェイスでスタックせず、すぐに終了します。btn_task_click はメイン スレッド タスクです。
次に、 continuewith() です。tasklist 内のスレッドが実行され、条件が満たされると (all\any)、次のようになります。コミッションは「ドヤ顔」などのコールバックと同様に、順番に直接実行されます。
4.taskfactory. continuewith()
5. 最大 11 スレッドのみが動作するように設計されています
6. taskfactory は終了したスレッドを検出すると、スレッド ID を返します。
7. メインスレッドのブロックを避けるために、タスクを複数回ネストすることができます。
8. 2 つの waitall が順番に実行されます。
実行する必要のある 2 つの waitall があり、それらは異なるスレッドにありますが、2 つの waitall の順序を保証する必要がある場合、解決策は、最初の waitall をタスクリストに追加し、2 番目のタスクの waitall に判断させることです。 。
9.thread.sleep() スレッドはスタックしますが、 task.delay() はスレッドをスタックさせません
10.タスクスレッド完了識別
6. .net4.5パラレル
1.Parallel はマルチスレッドを開始します
2.平行ねじ停止
7. スレッドコア
1.例外処理
メインスレッドで例外が発生すると、プログラムを管理する人がいないとプログラムがクラッシュします。
try {
TaskFactory taskFactory = new TaskFactory();
List < Task > tasklist = new List<Task>();
//异常处理
for(int i =0;i<20; i++)
{
string name = string.Format($"btn_click_{
i}");
Action<object> act = t =>
{
try
{
Thread.Sleep(2000);
if (t.ToString().Equals("btn_click_11"))
{
throw new Exception(string.Format($"{
t}执行失败"));
}
if (t.ToString().Equals("btn_click_12"))
{
throw new Exception(string.Format($"{
t}执行失败"));
}
Console.WriteLine("{0}执行成功", t);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
};
tasklist.Add(taskFactory.StartNew(act, name));
};
Task.WaitAll(tasklist.ToArray());
}
catch (AggregateException aex)
{
foreach(var item in aex.InnerExceptions)
{
Console.WriteLine(item.Message);
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
2. スレッドのキャンセル
tasklist.Add(taskFactory.StartNew(act, name)) 時、
tasklist.Add(taskFactory.StartNew(act, name,cts.Token)) 時、
try {
TaskFactory taskFactory = new TaskFactory();
List < Task > tasklist = new List<Task>();
CancellationTokenSource cts = new CancellationTokenSource();
for(int i =0;i<40; i++)
{
string name = string.Format($"btn_click_{
i}");
Action<object> act = t =>
{
try
{
/*
if (cts.IsCancellationRequested)
{
Console.WriteLine("{0}取消一个任务的执行",t);
}*/
Thread.Sleep(2000);
if (t.ToString().Equals("btn_click_11"))
{
throw new Exception(string.Format($"{
t}执行失败"));
}
if (t.ToString().Equals("btn_click_12"))
{
throw new Exception(string.Format($"{
t}执行失败"));
}
/*
else
{
Console.WriteLine("{0}执行成功", t);
}*/
if (cts.IsCancellationRequested)
{
Console.WriteLine("{0}放弃执行", t);
return;
}
else
{
Console.WriteLine("{0}执行成功", t);
}
}
catch (Exception ex)
{
cts.Cancel();
Console.WriteLine(ex.Message);
}
};
tasklist.Add(taskFactory.StartNew(act, name,cts.Token));
}
Task.WaitAll(tasklist.ToArray());
}
catch (AggregateException aex)
{
foreach(var item in aex.InnerExceptions)
{
Console.WriteLine(item.Message);
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
3. マルチスレッドの一時変数
4. スレッドセーフ ロック (ロックはリファレンスをロックします)
4.1 スレッドの安全性の問題
4.2 スレッド共有変数にはスレッド セーフティの問題がある
4.3ロック原理
1 つのスレッドのみが入ることができ、同時実行性がないため、問題は解決されますが、パフォーマンスが犠牲になります。Microsoft
定義のロックを使用することをお勧めします。
private static readonly object btn_click_lock = new object();//引用型变量
private int TotalCount = 0;
private List<int> IntList = new List<int>();
private void button1_Click(object sender, EventArgs e)
{
Console.WriteLine($"[------------主线程start: 线程号:({
Thread.CurrentThread.ManagedThreadId.ToString("00")})---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
TaskFactory taskFactory = new TaskFactory();
//private static readonly object btn_click_lock = new object();
List<Task> tasklist = new List<Task>();
for (int i = 0; i< 10000; i++)
{
int newI = i;
/*
//非多线程
this.TotalCount += 1;
this.IntList.Add(newI);*/
//多线程
tasklist.Add(taskFactory.StartNew(() =>
{
// int m = 3 + 2;
lock (btn_click_lock)
{
this.TotalCount += 1;
this.IntList.Add(newI);
}
}));
}
Task.WaitAll(tasklist.ToArray());
Console.WriteLine(this.TotalCount);
Console.WriteLine(this.IntList.Count());
Console.WriteLine($"[------------主线程end: 线程号:({
Thread.CurrentThread.ManagedThreadId.ToString("00")})---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
}
8、.net.0 await/async
1.待機原則
await の後のコードはコールバックに相当しますが、これは自分で記述したものではなく、コンパイラ ステート マシンに付属しています。
コールバックメソッド continuewith は子スレッドによって完了しますが、await は単なるコールバックではない (子スレッド、メインスレッド、またはコンピューターによって割り当てられる) ため、これらは異なります。
1.1 小規模コードのテストの原則
2. 戻り値のある非同期メソッドと戻り値のない非同期メソッド
2.1 のみ非同期
2.2asynic\await はペアで表示されます
await の後には戻り値のあるメソッドが続く必要があります
。async および await スイートを使用してメソッドを定義する場合、そのメソッドには戻り値がありませんが、このメソッドも戻り値があると見なすことができます。
戻り値を使用しないでください
戻り値を使用する
2.3 t.Wait() と await t の違い
2.4await 逆コンパイル - ステートマシンに相当
3. このナレッジポイントのコード
private void button1_Click(object sender, EventArgs e)
{
testshow();
}
public static void testshow()
{
test();
}
private async static Task test()
{
Console.WriteLine($"当前主线程id={
Thread.CurrentThread.ManagedThreadId.ToString("00")}---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
{
//NoReturnNoAwait();
NoReturn();
for (int i = 0; i < 10; i++)
{
Thread.Sleep(300);
Console.WriteLine($"main thread task managedthreadid={
Thread.CurrentThread.ManagedThreadId.ToString("00")}---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}--i={
i}");
}
}
}
private static async void NoReturn()
{
//主线程执行
Console.WriteLine($"NoReturn sleep before await ,threadid={
Thread.CurrentThread.ManagedThreadId.ToString("00")}---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
TaskFactory taskFactory = new TaskFactory();
Task task = taskFactory.StartNew(() =>
{
Console.WriteLine($"NoReturn sleep before ,threadid={
Thread.CurrentThread.ManagedThreadId.ToString("00")}---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
Thread.Sleep(300);
Console.WriteLine($"NoReturn sleep after ,threadid={
Thread.CurrentThread.ManagedThreadId.ToString("00")}---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
});
await task;
Console.WriteLine($"NoReturn sleep after await ,threadid={
Thread.CurrentThread.ManagedThreadId.ToString("00")}---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
}
private static async void NoReturnNoAwait()
{
//主线程执行
Console.WriteLine($"NoReturnNoAwait sleep before task ,threadid={
Thread.CurrentThread.ManagedThreadId.ToString("00")}---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
Task task = Task.Run(() =>
{
Console.WriteLine($"NoReturnNoAwait sleep before ,threadid={
Thread.CurrentThread.ManagedThreadId.ToString("00")}---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
Thread.Sleep(300);
Console.WriteLine($"NoReturnNoAwait sleep after ,threadid={
Thread.CurrentThread.ManagedThreadId.ToString("00")}---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
});
Console.WriteLine($"NoReturnNoAwait sleep after task ,threadid={
Thread.CurrentThread.ManagedThreadId.ToString("00")}---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
}
9. ダブルカラーボールプロジェクト
1.コード
知識のポイント
1. 7 つの独立したタスクにはマルチスレッド計算が必要です。7 つのスレッドを開始した後、スレッド メモリは計算を続けます。
2. 子スレッドはインターフェイスを更新できないため、this.Updatelbl(lbl, sNumber) を実装する必要があります。
3. while ( this.isgoon) から外部の 7 つのスレッドを終了します
。 4. ロック (llock) を使用して 7 つのサブスレッドをロックし、7 つのスレッドが同時に同じ値を持つのを防ぎます。 5. サブスレッドは待機し、
if (! this.isexsit(“00”) && !this.blue.Text.Equals(“00”))
6. すべてのサブスレッドの実行が終了したら、taskFactory.ContinueWhenAll(this.tasklist.ToArray(), t =) をコールバックします。 > this.ShowResult() );//
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace 双色球
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.start.Enabled = true;
this.stop.Enabled = false;
}
private string[] rednums = {
"01","02","03","04","05","06","07","08","09","10",
"11","12","13","14","15","16","17","18","19","20",
"21","22","23","24","25","26","27","28","29","30",
"31","32","33"
};
private string[] bluenums = {
"01","02","03","04","05","06","07","08","09","10",
"11","12","13","14","15","16"
};
private static readonly object llock =new object();
private bool isgoon = true;
private List<Task> tasklist = new List<Task>();
private void start_Click(object sender, EventArgs e)
{
try
{
this.start.Text = "运行ing";
this.start.Enabled = false;
this.isgoon = true;
this.tasklist = new List<Task>();
this.blue.Text = "00";
this.label1.Text = "00";
this.label2.Text = "00";
this.label3.Text = "00";
this.label4.Text = "00";
this.label5.Text = "00";
this.label6.Text = "00";
Console.WriteLine(new Random().Next(0, 15));
Console.WriteLine(new Random().Next(0, 15));
Console.WriteLine(new Random().Next(0, 15));
Console.WriteLine(new Random().Next(0, 15));
Thread.Sleep(1000);
TaskFactory taskFactory = new TaskFactory();
foreach(var control in this.groupBox1.Controls)
{
if (control is Label)//标签中
{
Label lbl = (Label)control;
if (lbl.Name.Contains("blue")) //blue
{
tasklist.Add( taskFactory.StartNew(() =>
{
while (this.isgoon)
{
int indexNum1 = Getrandombnumlong(0, bluenums.Length);
string sNumber = this.bluenums[indexNum1];
// lbl.Text = sNumber;
this.Updatelbl(lbl, sNumber);
}
}));
}
else//red
{
tasklist.Add( taskFactory.StartNew(() =>
{
while (this.isgoon)
{
int indexNum1 = Getrandombnumlong(0, this.rednums.Length);
string sNumber = this.rednums[indexNum1];
// lbl.Text = sNumber;
lock (llock)
{
if (this.isexsit(sNumber))//加锁防止random出现一样的值
{
continue;//重复数据时放弃更新
}
this.Updatelbl(lbl, sNumber);//7个线程访问的是内存中同一个string sNumber,加锁防止取到的值是重复的,
}
}
}));
}
}
}
//Thread.Sleep(3000);//直接等3000ms让stop开关enable,不靠谱,有可能有的线程因为数据重复,text没有更新
//this.stop.Enabled = true;
/*
while (true)
{
Thread.Sleep(1000);
if (!this.isexsit("00") && !this.blue.Text.Equals("00"))
{
this.stop.Enabled = true;
break;
}
}*/
Task.Run(()=> {
while (true)
{
Thread.Sleep(1000);
if (!this.isexsit("00") && !this.blue.Text.Equals("00"))
{
this.Invoke(new Action(()=>{
this.stop.Enabled = true;//子线程操控不了主线程控件,需要主线程来完成
}));
break;
}
}
});
taskFactory.ContinueWhenAll(this.tasklist.ToArray(), t => this.ShowResult() );//所有子线程都执行完
}
catch(Exception ex)
{
Console.WriteLine("双色球启动出现异常:{0}",ex.Message);
}
}
private void stop_Click(object sender, EventArgs e)
{
this.start.Enabled = true;
this.stop.Enabled = false;
this.isgoon = false;
//Task.WaitAll(this.tasklist.ToArray());//主线程等着全部任务完成,子任务还需要主线程干活更新label,所以又是死锁
//this.ShowResult();
}
private void ShowResult()
{
MessageBox.Show(string.Format("本期双色球为:{0} {1} {2} {3} {4} {5} 蓝球{6}"
, this.label1.Text
, this.label2.Text
, this.label3.Text
, this.label4.Text
, this.label5.Text
, this.label6.Text
, this.blue.Text ));
}
//更新界面
private void Updatelbl(Label lbl ,string text)
{
if (lbl.InvokeRequired)
{
//这里的this指的是winform窗体主UI线程,让UI线程去更新text值
this.Invoke(new Action(()=>{
//if (this.isgoon) //不延迟,点了就不更新
// {
lbl.Text = text;
Console.WriteLine($"当前update线程id{
Thread.CurrentThread.ManagedThreadId}");
// }
}));
}
else
{
lbl.Text = text;
}
}
//验证标签中的text是否有相同的值
private bool isexsit(string snumber)
{
foreach (var control in this.groupBox1.Controls)
{
if (control is Label)//标签中的
{
Label lbl = (Label)control;
if (lbl.Name.Contains("label"))
{
if (lbl.Text.Equals(snumber))
{
return true;
}
}
}
}
return false;
}
public int Getrandombnumlong(int min , int max)
{
int indexNum = new Random().Next(min, max);
Thread.Sleep(1000);
return indexNum;
}
}
}
10. ナレッジポイントコードの概要
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace multithread
{
public class Class1
{
private void dosomething(string name)
{
Console.WriteLine($"[****Dosomething {
name} start: 线程号:({
Thread.CurrentThread.ManagedThreadId.ToString("00")})---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}*******]");
}
//
//Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
private void mainpoints() {
//1委托调用
Action<string> action = this.dosomething;//委托带参数
Action action1 = () => this.dosomething("CC");//委托不带参数
action.Invoke("AA");//同步调用委托
action("BB");//同步调用委托
action.BeginInvoke("cc", null, null);//异步调用委托
for (int i = 0; i < 5; i++)
{
string name = string.Format($"btn_click_{
i}");
action.BeginInvoke(name, null, null);//异步多线程
}
List<Task> tasklist = new List<Task>();
TaskFactory taskFactory = new TaskFactory();
string name1 = string.Format($"btn_click");
CancellationTokenSource cts = new CancellationTokenSource();
Action<object> act = t =>
{
if (t.ToString().Equals("btn_click_11"))
{
throw new Exception(string.Format($"{
t}执行失败"));
}
};
tasklist.Add(taskFactory.StartNew(act, name1, cts.Token));
//2.委托执行完后进行回调
//标准写法
AsyncCallback callback = new AsyncCallback(i => Console.WriteLine($"[------------到这里计算完成: 线程号:({
Thread.CurrentThread.ManagedThreadId.ToString("00")})---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]"));
//简单写法
AsyncCallback callback1 = i =>
{
Console.WriteLine($"[------------到这里计算完成: 线程号:({
Thread.CurrentThread.ManagedThreadId.ToString("00")})---{
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");
};
action.BeginInvoke("cc", callback, null);
//回调1 -异步action执行完才会执行回调-action.BeginInvoke("cc", callback, "nimen")-1
IAsyncResult asyncResult = null;
asyncResult = action.BeginInvoke("cc", callback, "nimen");
//回调1 - 异步action执行完才会执行回调 - action.BeginInvoke("cc", callback, "nimen")-2
action.BeginInvoke("cc", r =>
{
Console.WriteLine("11");
}, "nimen");
//回调2 -异步action执行完才会执行回调-(!asyncResult.IsCompleted)
while (!asyncResult.IsCompleted)
{
Console.WriteLine($"文件上传99.9%..");
}
//回调3 -异步action执行完才会执行回调--信号量WaitOne()
asyncResult.AsyncWaitHandle.WaitOne();//等待异步任务完成后,才打印计算完成
asyncResult.AsyncWaitHandle.WaitOne(2000);//限时等待
// 回调4 - 异步action执行完才会执行回调 - EndInvoke拿到委托函数的返回值
Func<int> func = () =>
{
return DateTime.Now.Day;
};
Console.WriteLine($"func.Invoke()={
func.Invoke()}");
IAsyncResult asyncResult1 = func.BeginInvoke(r =>
{
Console.WriteLine(r.AsyncState);
}, "nimen");
Console.WriteLine($"func.EndInvoke={
func.EndInvoke(asyncResult1)}");
//3.thread
//3.1.线程启动 thread.Start();
ThreadStart threadStart = () => this.dosomething("cc");
Thread thread = new Thread(threadStart);
thread.Start();
//3.2.线等待程thread.Join();
thread.Join(500);//卡主线程
Console.WriteLine($"等待500ms");
thread.Join();
//3.3.thread.ThreadState /thread.IsBackfround
while (thread.ThreadState != ThreadState.Stopped)
{
Thread.Sleep(100);//cpu时间片交出去干其他的事,但是内存还是占用
}
thread.IsBackground = true;//前台线程,当软件闪退时,会吐出日志
//4.threadPool
//4.1ThreadPool.GetMaxThreads
ThreadPool.QueueUserWorkItem(
t =>
{
this.dosomething("cc");
this.dosomething("dd");
});//接收一个没有返回值的委托
ThreadPool.SetMaxThreads(16, 16);
ThreadPool.GetMaxThreads(out int Workerthreads, out int completionPortThreads);
Console.WriteLine($"Workerthreads:{
Workerthreads}+completionPortThreads{
completionPortThreads}");
//4.2.manualResetEvent
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(t =>
{
this.dosomething("cc");
manualResetEvent.Set();
});//接收一个没有返回值的委托
manualResetEvent.WaitOne();
Console.WriteLine($"等待ThreadPool.QueueUserWorkItem执行完再执行");
//5.task
Task.Run(() =>
{
this.dosomething("cc");
Console.WriteLine($"等待ThreadPool.QueueUserWorkItem执行完再执行");
});
new Task(() => this.dosomething("33")).Start();
TaskFactory taskFactory1 = Task.Factory;
taskFactory.StartNew(() => this.dosomething("44"));
//5.1 task.waitall、waitany .ContinueWith taskFactory.ContinueWhenAny
List<Task> tasklist1 = new List<Task>();
tasklist.Add(Task.Run(() => this.dosomething("33")));
tasklist.Add(Task.Run(() => this.dosomething("33")));
Task.WaitAny(tasklist.ToArray());
Task.WaitAll(tasklist.ToArray());
Task.WhenAll(tasklist.ToArray()).ContinueWith(t =>
{
Console.WriteLine($"等待ThreadPool.QueueUserWorkItem执行完再执行");
});
taskFactory.ContinueWhenAny(tasklist.ToArray(), t => {
});
//5.2 task线程完成标识
Task task = new Task(t => {
}, "CC");
Console.WriteLine(task.AsyncState);//会打印CC
//5.3thread.sleep()卡线程 task.delay()不卡线程
//5.4tasklist线程取消
CancellationTokenSource cts1 = new CancellationTokenSource();
tasklist.Add(taskFactory.StartNew(() => this.dosomething("44"), cts1.Token));
//6.parallel启动多线程
Parallel.Invoke(
() => this.dosomething("11"),
() => this.dosomething("22"),
() => this.dosomething("33")
);
//6.1Parallel.For
Parallel.For(0, 5, i => this.dosomething(i));
Parallel.ForEach(new string[] {
"0","1","2","3"},i=>this.dosomething("11"));
//6.2控制并发数量
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = 3;
Parallel.For(0,40,parallelOptions,(i,state)=> {
if (i==2)
{
state.Break();
state.Stop();
}
});
//7.线程安全lock
//private static readonly object btn_click = new object();
int c = 0;
tasklist.Add(taskFactory.StartNew(() => {
int m = 3 + 2;
lock (btn_click)
{
c += 1;
}
}));
//8.await/asyncawait 后的代码相当于回调,只不过不是自己写的,是编译器状态机自带的。
//回调方法continuewith是子线程完成的,但await不仅仅是回调(可子线程可主线程,计算机分配),所以他们又有所不同
private static async void Async()
{
await Task.Run(() =>
{
Console.WriteLine($"等待ThreadPool.QueueUserWorkItem执行完再执行");
});
Console.WriteLine($"等待ThreadPool.QueueUserWorkItem执行完再执行");
}
}
}
}