C#线程暂停和继续操作 (Thread及Task) 多线程的异常如何捕捉, 多个线程返回结果合计 监视锁
多线程异常的捕捉:需要批量的等待: Task.WaitAll(tasklist.ToArray());
摘自:https://www.cnblogs.com/LcVong/p/12651599.html
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 XCZT
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Label.CheckForIllegalCrossThreadCalls = false;
}
ManualResetEvent ma = new ManualResetEvent(false);
bool stop = false;
//启动
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(Runtime);
stop = false;
ma.Set();// 信号打开,不阻塞当前线程
thread.Start();
}
/// <summary>
/// 线程
/// </summary>
void Runtime()
{
for (int i = 1; i <= 100; i++)
{
if (stop)
{
return;
}
ma.WaitOne();//根据是否收到信号判断是否阻塞当前线程
textBox1.AppendText("计时 :" + i + "\r\n");
Thread.Sleep(100);
}
}
//暂停
private void button2_Click(object sender, EventArgs e)
{
ma.Reset();//信号关闭阻塞当前线程
textBox1.AppendText("暂停中 :\r\n");
}
//继续
private void button3_Click(object sender, EventArgs e)
{
ma.Set();//信号打开,不阻塞当前线程
textBox1.AppendText("继续计时 :\r\n");
}
//停止
private void button4_Click(object sender, EventArgs e)
{
stop = true;
textBox1.AppendText("停止计时 \r\n");
}
}
}

Task
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 WindowsFormsApp1
{
public partial class Form4 : Form
{
private CancellationTokenSource cts = null;
public Form4()
{
InitializeComponent();
Label.CheckForIllegalCrossThreadCalls = false;
}
ManualResetEvent ma = new ManualResetEvent(true);
bool stop = false;
//启动
private void button1_Click(object sender, EventArgs e)
{
//Thread thread = new Thread(Runtime);
cts = new CancellationTokenSource();
Task task = new Task(()=>Runtime(),cts.Token);
stop = false;
ma.Set();// 信号打开,不阻塞当前线程
task.Start();
}
/// <summary>
/// 线程
/// </summary>
async void Runtime()
{
for (int i = 1; i <= 100; i++)
{
if (stop)
{
return;
}
if (cts.IsCancellationRequested) return;
ma.WaitOne();//根据是否收到信号判断是否阻塞当前线程
textBox1.AppendText("计时 :" + i + "\r\n");
//Thread.Sleep(100);
await Task.Delay(100);
}
}
//暂停
private void button2_Click(object sender, EventArgs e)
{
ma.Reset();//信号关闭阻塞当前线程
textBox1.AppendText("暂停中 :\r\n");
}
//继续
private void button3_Click(object sender, EventArgs e)
{
ma.Set();//信号打开,不阻塞当前线程
textBox1.AppendText("继续计时 :\r\n");
}
//停止
private void button4_Click(object sender, EventArgs e)
{
//stop = true;
cts.Cancel();
textBox1.AppendText("停止计时 \r\n");
}
}
}
多个线程返回结果合计


Web线程等待 自己写异步线程
public partial class Form5 : Form
{
public Form5()
{
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
textBox1.Text = "";
#region 不够优雅
//WebClient webClient = new WebClient();
//Task.Run(() =>
//{
// string html = webClient.DownloadString("https://www.youtube.com"); //如果不开线程会堵塞
// this.Invoke(new Action(() =>
// {
// textBox1.Text = html; //.Substring(1,20);
// }));
//});
#endregion
/*
//(1) 卡界面
HttpClient httpClient = new HttpClient();
Task<string> t = httpClient.GetStringAsync("https://www.youtube.com");
string html = t.Result;
textBox1.Text = html;
*/
//(2) 不卡界面
//HttpClient httpClient = new HttpClient();
//Task<string> t = httpClient.GetStringAsync("https://www.youtube.com");
//string html = await t;
//textBox1.Text = html;
/*
//(3) 不卡界面 更简写, 优雅
HttpClient httpClient = new HttpClient();
string html =await httpClient.GetStringAsync("https://www.youtube.com");
textBox1.Text = html;
*/
//下面试着写自己的异步函数
string html =await MyDownloadAsync("https://www.youtube.com");
textBox1.Text = html;
}
/*
private Task<string> MyDownloadAsync(string url)
{
WebClient webClient = new WebClient();
return Task.Run(() =>
{
return webClient.DownloadString(url);
});
}
*/
//加了await, 不过好象没什么用 (多线程是实现异步的其中一种手段, 已经是多线程了, 应该是不用加await了)
private async Task<string> MyDownloadAsync(string url)
{
WebClient webClient = new WebClient();
return await Task.Run(() =>
{
return webClient.DownloadString(url);
});
}
}
范型与共享锁变量


region 监视锁:Lock 限制线程个数的一把锁
//为什么要用锁?在多线程中,尤其是静态资源的访问,必然会有竞争
private static int nums = 0;
private static object myLock = new object();1 个引用
static void Method12()
{
for (int i =0;i<5;i++)
{
Task.Factory.StartNew(()=>
{
TestMethod();
});
}
}
static void TestMethod()
{
for (int i = 0;i< 100;i++)
{
lock(myLock)
{
nums++;
Console.WriteLine(nums):
}
}
}
//Lock是Monitor语法糖,本质是解决资源的锁定问题
//我们锁住的资源一定是让线程可访问到的,所以不能是局部变量。
//锁住的资源千万不要是值类型。
//lock也不能锁住string类型。
浙公网安备 33010602011771号