using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AsyncThreads
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnSync_Click(object sender, EventArgs e)
{
Console.WriteLine($"***btnSync_Click {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
People p = new People();
for (int i = 0; i < 5; i++)
{
string name = $"btnSync_Click_{i}";
this.DoSomethingLong(p);
}
Console.WriteLine($"btnSync_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
}
private void btnAsync_Click(object sender, EventArgs e)
{
People p = new People();
Console.WriteLine($"***btnASync_Click {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
Action<People> action = this.DoSomethingLong;
//action += s => Console.WriteLine("aaaa");//action要执行BeginInvoke只能注册一个方法
for (int i = 0; i < 5; i++)
{
string name = $"btnSync_Click_{i}";
action.BeginInvoke(p, null, null);
}
Console.WriteLine("btnASync_Click End");
}
private void btnAsyncAdvance_Click(object sender, EventArgs e)
{
Console.WriteLine($"***btnAsyncAdvance_Click {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
Action<People> action = this.DoSomethingLong;
People p = new People();
IAsyncResult ar0 = null;
//1 回调事件
AsyncCallback asyncCallback = ar =>
{
Console.WriteLine($"btnAsyncAdvance_BeginInvoke End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {(ar.AsyncState as People).Name}");
};
ar0 = action.BeginInvoke(p, asyncCallback, p);//传入参数,回调事件,传给回调事件的参数
//2 判断异步委托是否执行完成
//int i = 0;
//while (!ar0.IsCompleted)
//{
// if (i < 9)
// {
// Console.WriteLine($"中华民族觉醒{++i * 10}%");
// }
// else
// {
// Console.WriteLine($"中华民族觉醒99.9%");
// }
// Thread.Sleep(400);
//}
//3 等待异步委托完成
//ar0.AsyncWaitHandle.WaitOne();
//ar0.AsyncWaitHandle.WaitOne(-1);//无限等待
//ar0.AsyncWaitHandle.WaitOne(500);//等待指定毫秒
//4 EndInvoke等待异步委托完成
action.EndInvoke(ar0);
//EndInvoke还可以获取返回值
{
Func<int> func = () => System.DateTime.Now.Hour;
IAsyncResult arfunc = func.BeginInvoke(ar =>
{
//EndInvoke 也可以用在回调里面,但是一个BeginInvoke只能对应一个EndInvoke
//int arRst = func.EndInvoke(ar);
//Console.WriteLine($"arRst={arRst}");
}, null);
func.BeginInvoke(null, null);
int rst = func.EndInvoke(arfunc);
Console.WriteLine($"rst={rst}");
}
Console.WriteLine("中华民族觉醒-->看招!!!");
Console.WriteLine("btnAsyncAdvance_Click End");
}
#region .NetFramework 1.0 出现Thread
private void btnThread_Click(object sender, EventArgs e)
{
Console.WriteLine($"***btnASync_Click {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
{
//People p = new People();
//p.Name = "小王";
//ThreadStart method = () => this.DoSomethingLong(p);
//Thread thread = new Thread(method);
//thread.Start();
}
{
//People p = new People();
//p.Name = "大王";
//ParameterizedThreadStart method = obj =>
//{
// Thread.Sleep(5000);
// this.DoSomethingLong(p);
// Thread.Sleep(5000);
//};
//Thread thread = new Thread(method);
//thread.Start("111");
#region 不建议的写法
//thread.Suspend();//挂起线程(已过时)
//thread.Resume();//恢复线程(已过时)
//thread.Abort();//停止线程(不是真停止,只能停止程序,不接收相应,但是启用的计算机资源并不会停,比如硬盘读写)
//Thread.ResetAbort();//恢复停止的线程
#endregion
//等待方式1
//while (thread.ThreadState != ThreadState.Stopped)
//{
// Thread.Sleep(200);
//}
//等待方式2
//thread.Join();//等待thread线程完成
//thread.Join(200);//等待thread线程最多200ms
//thread.Priority = ThreadPriority.Normal;//指定线程执行的优先级,但保证不了完成的优先级
//thread.IsBackground = true;//后台线程,关闭主线程,后台线程结束
//thread.IsBackground = false;//默认是false,前台线程,主线程关闭,不影响前台线程
}
{
//People p = new People();
//ThreadStart threadStart = () => this.DoSomethingLong(p);
//Action actionCallback = () => Console.WriteLine("actionCallback");
//ThreadWithCallback(threadStart, actionCallback);
}
{
Func<int> func = () =>
{
Console.WriteLine($"***func {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
Thread.Sleep(5000);
Console.WriteLine("func End");
return 521;
};
Func<int> funcRst = ThreadWithReturn(func);
int rst = funcRst.Invoke();
Console.WriteLine(rst);
}
Console.WriteLine("btnThread_Click End");
}
//封装一个没有返回值的异步带回调的方法
private void ThreadWithCallback(ThreadStart threadStart, Action actionCallback)
{
ThreadStart ts = () =>
{
threadStart.Invoke();
actionCallback.Invoke();
};
Thread thread = new Thread(ts);
thread.Start();
}
//封装一个有返回值的异步的方法
private Func<T> ThreadWithReturn<T>(Func<T> func)
{
//非阻塞
//获取返回值的时候是阻塞的
T t = default(T);
ThreadStart ts = () =>
{
t = func.Invoke();
};
Thread thread = new Thread(ts);
thread.Start();
return () =>
{
thread.Join();
return t;
};
}
#endregion
#region .NetFramework 2.0 出现ThreadPool
private void btnThreadPool_Click(object sender, EventArgs e)
{
//线程池的线程都是后台线程
//线程的创建和销毁交给线程池了,提高资源的利用率
//控制线程的数量
//People p = new People();
//ThreadPool.QueueUserWorkItem(obj => this.DoSomethingLong(p));
//ThreadPool.QueueUserWorkItem(this.DoSomething, p);
//ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);//2015还不支持传参时定义out变量
#region 线程池设置的最大/最小线程数量
{
//线程池设置的最大/最小线程数量针对线程全局
//委托异步调用/Task/Parrallel/async/await 等都是线程池的线程
//直接new Thread的这种不受线程池设置的影响,但是new Thread会占用线程池的数量
//int workerThreads = 0;
//int completionPortThreads = 0;
//int minWorkerThreads = 0;
//int minCompletionPortThreads = 0;
//ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
//ThreadPool.GetMinThreads(out minWorkerThreads, out minCompletionPortThreads);
//Console.WriteLine($"workerThreads:{workerThreads},completionPortThreads:{completionPortThreads}");
//Console.WriteLine($"minWorkerThreads:{minWorkerThreads},minCompletionPortThreads:{minCompletionPortThreads}");
//ThreadPool.SetMaxThreads(8, 8);//设置最大线程数 不能小于电脑核数 否则不起作用
//ThreadPool.SetMinThreads(2, 2);
//ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
//ThreadPool.GetMinThreads(out minWorkerThreads, out minCompletionPortThreads);
//Console.WriteLine($"workerThreads:{workerThreads},completionPortThreads:{completionPortThreads}");
//Console.WriteLine($"minWorkerThreads:{minWorkerThreads},minCompletionPortThreads:{minCompletionPortThreads}");
}
#endregion
#region 等待
//false默认关闭--Set开启--WaitOne等待Set后执行后面的代码
//true默认开启--Reset关闭--Reset后WaitOne阻塞后面的代码
//ManualResetEvent manualResetEvent = new ManualResetEvent(false);
//ThreadPool.QueueUserWorkItem(obj =>
//{
// People p = new People();
// manualResetEvent.Reset();
// this.DoSomethingLong(p);
// manualResetEvent.Set();
//});
//Console.WriteLine("do something else...");
//Console.WriteLine("do something else...");
//Console.WriteLine("do something else...");
//Console.WriteLine("do something else...");
//manualResetEvent.WaitOne();
//Console.WriteLine("btnThreadPool_Click End");
#endregion
#region 死锁(小心使用Set,避免多个线程之间等待的关系)
{
ThreadPool.SetMaxThreads(8, 8);
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
for (int i = 0; i < 10; i++)
{
int k = i;
ThreadPool.QueueUserWorkItem(obj =>
{
Console.WriteLine($"***ThreadPool {Thread.CurrentThread.ManagedThreadId.ToString("00")} k:{k}");
if (k == 9)
manualResetEvent.Set();
else
manualResetEvent.WaitOne();
});
}
if (manualResetEvent.WaitOne())
{
Console.WriteLine($"All thread in threadpool had ended");
}
}
#endregion
}
#endregion
#region .NetFramework 3.0 出现Task
private void btnTask_Click(object sender, EventArgs e)
{
//Task的线程都是基于线程池的
Console.WriteLine($"***btnTask_Click {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
#region 启动方式
//{
// Task task = new Task(() => DoSomethingLong(new People()));
// task.Start();
//}
//{
// Task task = Task.Run(() => DoSomethingLong(new People()));
//}
//{
// Task task = new TaskFactory().StartNew(() => DoSomethingLong(new People()));
//}
#endregion
#region Sleep 和Delay
//sleep 是同步等待
//delay 是异步等待--延迟启动
//{
// Console.WriteLine($"Sleep start");
// Stopwatch stopwatch = new Stopwatch();
// stopwatch.Start();
// Thread.Sleep(2000);
// //Task.Run(() => DoSomethingLong(new People()));
// stopwatch.Stop();
// Console.WriteLine($"耗时{stopwatch.ElapsedMilliseconds}");
// Console.WriteLine($"Sleep end");
//}
//{
// Console.WriteLine($"Delay start");
// Stopwatch stopwatch = new Stopwatch();
// stopwatch.Start();
// Task.Delay(2000).ContinueWith(t =>
// {
// stopwatch.Stop();
// Console.WriteLine($"耗时{stopwatch.ElapsedMilliseconds}");
// DoSomethingLong(new People());
// });
// Console.WriteLine($"Delay end");
//}
//{
// //ContinueWith 其实就是回调
// Task.Run(() => DoSomething(new People())).ContinueWith(t => Console.WriteLine($"回调 {Thread.CurrentThread.ManagedThreadId}"));
//}
//{
// //带返回值的线程
// Task<int> task = Task.Run<int>(() =>
// {
// Thread.Sleep(1000);
// return DateTime.Now.Year;
// });
// int rst = task.Result;
// Console.WriteLine(rst);
//}
#endregion
#region 一个例子
{
//多线程用在什么地方?
//可以并发执行的任务
//相反,有顺序限制,不可分割的动作就用不了
Console.WriteLine($"Eleven老师开始一学期的课程");
Teach("lenssen_0");
Teach("lenssen_1");
Teach("lenssen_2");
Console.WriteLine($"布置了一个期末测试项目");
TaskFactory taskFactory = new TaskFactory();
List<Task> taskList = new List<Task>();
taskList.Add(Task.Run(() => Coding("小高", "充值")));
//taskList.Add(Task.Run(() => Coding("小悦", "订单")));
Task.Delay(0).ContinueWith((o, s) => Coding("小悦", "订单"), "小悦");//传入参数,供回调使用
taskList.Add(taskFactory.StartNew(() => Coding("小王", "权限")));
taskList.Add(taskFactory.StartNew(o => Coding("大王", "推送"), "大王"));//传入参数,供回调使用
//非阻塞
taskFactory.ContinueWhenAny(taskList.ToArray(), t => Console.WriteLine($"{t.AsyncState} 异步方式任意一个线程完成 {Thread.CurrentThread.ManagedThreadId}"));
//小套路,可以把等待全部线程结束的子线程也放入线程列表中,这样保证该线程执行在阻塞的等待全部完成之前
taskList.Add(taskFactory.ContinueWhenAll(taskList.ToArray(), t => Console.WriteLine($"异步方式全部线程完成 {Thread.CurrentThread.ManagedThreadId}")));
//阻塞的
Task.WaitAny(taskList.ToArray());
Console.WriteLine("第一个模块已经完成");
Task.WaitAll(taskList.ToArray());
Console.WriteLine("项目完成,开始点评");
}
#endregion
{
//使用task并控制线程的数量
//for (int i = 0; i < 1000; i++)
//{
// int k = i;
// List<Task> taskList = new List<Task>();
// if (taskList.Count(t => t.Status != TaskStatus.RanToCompletion) > 19)
// {
// Task.WaitAny(taskList.ToArray());
// taskList = taskList.Where(t => t.Status != TaskStatus.RanToCompletion).ToList();
// }
// taskList.Add(Task.Run(() => Console.WriteLine($"明日复明日,明日何其多 {k}")));
//}
}
Console.WriteLine("btnTask_Click End");
}
#endregion
#region Parallel
private void btnParallel_Click(object sender, EventArgs e)
{
//Parallel会让主线程参与多线程的计算,所以会阻塞
Console.WriteLine($"***btnParallel_Click {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
//Parallel.Invoke(() => Console.WriteLine($"Parallel执行0 ThreadId:{Thread.CurrentThread.ManagedThreadId.ToString("00")}"),
// () => Console.WriteLine($"Parallel执行1 ThreadId:{Thread.CurrentThread.ManagedThreadId.ToString("00")}"),
// () => Console.WriteLine($"Parallel执行2 ThreadId:{Thread.CurrentThread.ManagedThreadId.ToString("00")}"),
// () => Console.WriteLine($"Parallel执行3 ThreadId:{Thread.CurrentThread.ManagedThreadId.ToString("00")}"));
//Parallel.For(0, 5, i =>
//{
// Console.WriteLine($"Parallel执行{i} ThreadId:{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
// Thread.Sleep(2000);//不加等待执行过快,全是主线程在跑
//});
//Parallel.ForEach(new int[] { 0, 1, 2, 3, 4 }, i =>
// {
// Console.WriteLine($"Parallel执行{i} ThreadId:{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
// Thread.Sleep(2000);//不加等待执行过快,全是主线程在跑
// });
{
//控制线程数量
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = 3;//线程数量设为3
Parallel.For(0, 10, parallelOptions, i =>
{
Console.WriteLine($"Parallel执行{i} ThreadId:{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
Thread.Sleep(2000);//不加等待执行过快,全是主线程在跑
});
}
Console.WriteLine($"btnParallel_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
}
#endregion
private void btnThreadCore_Click(object sender, EventArgs e)
{
//多线程中的异常会终结当前线程,不会影响其他线程,异常会被吞
Console.WriteLine($"***btnThreadCore_Click {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
#region 异常处理
//try
//{
// List<Task> taskList = new List<Task>();
// for (int i = 0; i < 10; i++)
// {
// int k = i;
// taskList.Add(Task.Run(() =>
// {
// try
// {
// if (k == 3)
// {
// throw new Exception("3异常");
// }
// else if (k == 6)
// {
// throw new Exception("6异常");
// }
// Console.WriteLine($"***TaskRun_{k} {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
// }
// catch (Exception ex)//一般不允许线程里面出现错误,捕获异常,自己处理
// {
// Console.WriteLine(ex.Message);
// }
// }));
// }
// Task.WaitAll(taskList.ToArray());//可以捕获线程的异常
//}
//catch (AggregateException aex)//AggregateException 多线程异常
//{
// foreach (var exce in aex.InnerExceptions)
// {
// Console.WriteLine(exce.Message);
// }
//}
//catch (Exception ex)
//{
// Console.WriteLine(ex.Message);
//}
//通常不允许多线程里出现错误,所以要在多线程中加try-catch
#endregion
#region 线程取消 其实是多线程任务的终止,线程跑起来没法从外部取消
//线程执行起来并不能从外部取消,所以要做到取消,只能是在线程执行前加判断和信号量,如果信号量改变,就不让线程启动,这样模拟多线程任务的终止
//1.准备cts 2.try-catch-cts.Cancel 3.线程中取消的动作前判断IsCancellationRequested 4.信号量的发出到判断环节的接收 会有延迟
//Task.Run(Action action, CancellationToken cancellationToken) 传cts.Token 进去,接收到信号,没有开始的线程就不启动了
//CancellationTokenSource cts = new CancellationTokenSource();//信号量,初始化属性IsCancellationRequested是false
//List<Task> taskList = new List<Task>();
//try
//{
// for (int i = 0; i <= 50; i++)
// {
// int k = i;
// taskList.Add(Task.Run(() =>
// {
// try
// {
// Console.WriteLine($"task_{k}_start {Thread.CurrentThread.ManagedThreadId}");
// Thread.Sleep(new Random().Next(5, 10) * 100);
// if (k == 8 || k == 10)
// {
// throw new Exception($"task_{k}_err");
// }
// if (!cts.IsCancellationRequested)
// {
// Console.WriteLine($"task_{k}_end");
// }
// else
// {
// Console.WriteLine($"task_{k}_cancel");
// }
// }
// catch (Exception ex)
// {
// Console.WriteLine(ex.Message);
// cts.Cancel();
// }
// }, cts.Token));
// }
// Task.WaitAll(taskList.ToArray());//会引起cts.Token已经取消执行的线程报出异常
//}
//catch (AggregateException aex)//AggregateException 多线程异常
//{
// foreach (var exce in aex.InnerExceptions)
// {
// Console.WriteLine(exce.Message);
// }
//}
//catch (Exception ex)
//{
// Console.WriteLine(ex.Message);
//}
#endregion
#region 临时变量
//线程启动是需要时间的,此时i已经很快跑到5了
//由于每个循环的k是一个新的变量,所以用k作为每次循环的标志
//for (int i = 0; i < 5; i++)
//{
// int k = i;
// Task.Run(() =>
// {
// Console.WriteLine($"task_{i}_{k}");
// });
//}
#endregion
#region 线程安全 lock
//1.全局变量、共享变量、静态变量、文件、数据库都要考虑线程安全的问题,凡是能被多个线程改变的东西,是要考虑安全的
// 推荐写法:private static readonly object objLock = new Object();
// lock 锁的应该是引用类型
// lock(this)的问题,如果在类外要锁实例,会发生冲突 锁是针对多线程的,单线程是不起作用的
// lock(string) 如果类外锁的string内容与类内锁的内容相同,会发生冲突
//2.线程安全的集合,都在这个域名下
// System.Collections.Concurrent.ConcurrentQueue<int> ccQueue = new System.Collections.Concurrent.ConcurrentQueue<int>();
//3.数据分拆,避免多线程操作同一块数据
{
Test test = new Test();
Task.Delay(1000).ContinueWith(t =>
{
lock (test)//这个实例与Test类中的this冲突了,按先后顺序,一个锁执行完成,才会走另一个锁
{
Console.WriteLine("ContinueWith Start");
Thread.Sleep(1000);
Console.WriteLine("ContinueWith End");
}
});
test.TestLock();//递归的过程中这个锁是不起作用的,不会锁线程自己
//string strMyLock = "小高";
//Task.Delay(1000).ContinueWith(t =>
//{
// lock (strMyLock)//这个实例与Test类中的strLock值一样 冲突了,按先后顺序,一个锁执行完成,才会走另一个锁
// {
// Console.WriteLine("ContinueWithString Start");
// Thread.Sleep(1000);
// Console.WriteLine("ContinueWithString End");
// }
//});
//test.TestLockString();
Thread.Sleep(10000);
}
{
for (int i = 0; i < 1000; i++)
{
iSync++;
}
List<Task> taskList = new List<Task>();
//不加锁,多线程赋值同一个全局变量是不安全的
//for (int i = 0; i < 1000; i++)
//{
// taskList.Add(Task.Run(() => iAsync++));
//}
for (int i = 0; i < 1000; i++)
{
taskList.Add(Task.Run(() =>
{
lock (objLock)
{
iAsync++;
}
}));
}
Task.WaitAll(taskList.ToArray());
Console.WriteLine($"iSync={iSync} iAsync={iAsync}");
}
#endregion
Console.WriteLine("btnThreadCore_Click End");
}
private int iSync = 0;
private int iAsync = 0;
private static readonly object objLock = new object();
public class Test
{
public void TestLock()
{
this.iTest++;
lock (this)//递归的过程中这个锁是不起作用的,不会锁线程自己
{
if (iTest < 10)
{
Thread.Sleep(500);
Console.WriteLine($"iTest={iTest}");
this.TestLock();
}
else
{
Console.WriteLine($"iTest={iTest} end!!!!!!!!!");
}
}
}
public void TestLockString()
{
this.iTest++;
lock (strLock)//递归的过程中这个锁是不起作用的,不会锁线程自己
{
if (iTest < 10)
{
Thread.Sleep(500);
Console.WriteLine($"iTestString={iTest}");
this.TestLockString();
}
else
{
Console.WriteLine($"iTestString={iTest} end!!!!!!!!!");
}
}
}
private int iTest = 0;
private string strLock = "小高";
}
private void DoSomethingLong(People p)
{
Console.WriteLine($"***DoSomethingLong {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
Console.WriteLine($"Name:{p.Name}");
Thread.Sleep(4000);
p.Name = "小高";
Console.WriteLine("DoSomethingLong End");
}
private void DoSomething(object p)
{
People people = p as People;
Console.WriteLine($"Name:{people?.Name}");
}
private void Teach(string lensson)
{
Console.WriteLine($"教授课程{lensson}");
}
private void Coding(string name, string mode)
{
Console.WriteLine($"{name}同学做{mode}模块 {Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(1000);
}
public class People
{
private string _name;
private readonly object obj = new object();
public string Name
{
set
{
lock (obj)
{
_name = value;
}
}
get { return _name; }
}
}
}
}
双色球练习:
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 AsyncThreads
{
public partial class Form2 : Form
{
private List<int> redList = new List<int>();
private List<int> blueList = new List<int>();
private CancellationTokenSource cts = new CancellationTokenSource();
private static readonly object objLock = new object();
List<Task> taskList = new List<Task>();
public Form2()
{
InitializeComponent();
this.btnStop.Enabled = false;
for (int i = 0; i < 33; i++)
{
redList.Add(i + 1);
if (i < 16)
blueList.Add(i + 1);
}
}
private void btnStart_Click(object sender, EventArgs e)
{
//多线程取随机数不能用Random,结果很可能相同
//子线程不能操作UI,需要委托给主线程this.Invoke,这种其实是同步执行的
this.btnStart.Enabled = false;
foreach (var control in gbxResult.Controls)
{
if (control is Label)
{
Label label = (Label)control;
if (label.Name.Equals("lab6"))
{
taskList.Add(Task.Run(() =>
{
while (!cts.IsCancellationRequested)
{
int number = GetDelayRandomNumber(0, 16);
this.Invoke(new Action(() => label.Text = number.ToString().PadLeft(2, '0')));
}
}));
}
else
{
taskList.Add(Task.Run(() =>
{
while (!cts.IsCancellationRequested)
{
int number = GetDelayRandomNumber(0, 33);
lock (objLock)
{
List<int> intList = GetInterFaceNumber();
if (!intList.Contains(number))
{
this.Invoke(new Action(() => label.Text = number.ToString().PadLeft(2, '0')));
}
}
}
}));
}
}
}
Task.Factory.ContinueWhenAll(taskList.ToArray(), t => ShowMessage());
Task.Delay(10 * 1000).ContinueWith(t =>
{
this.Invoke(new Action(() => this.btnStop.Enabled = true));
});
#region 第一次写的差代码
//for (int i = 0; i < 7; i++)
//{
// int k = i;
// //多线程取随机数不能用Random,结果很可能相同
// //Random rdm = new Random();
// int number = 0;
// Task.Run(() =>
// {
// try
// {
// while (!cts.IsCancellationRequested)
// {
// //有重复需要去重,读取界面当前的数据,判断现在生成的这个数是否在界面中,这个步骤要加锁
// number = GetDelayRandomNumber(0, 33);
// if (k == 6)
// {
// number = GetDelayRandomNumber(0, 16);
// }
// var label = gbxResult.Controls[k];
// //label.Text = number.ToString().PadLeft(2, '0');//子线程不能操作UI,需要委托给主线程this.Invoke
// this.Invoke(new Action(() => label.Text = number.ToString().PadLeft(2, '0')));
// };
// }
// catch (Exception ex)
// {
// Console.WriteLine(ex.Message);
// }
// });
//}
#endregion
}
private void btnStop_Click(object sender, EventArgs e)
{
this.btnStart.Enabled = true;
this.btnStop.Enabled = false;
cts.Cancel();
//获取此刻数据会有错误的,停止按钮点了,但是线程有可能还没结束,面板上的数据和最终的数据有可能是不一样的,
//所以必须等待所有线程结束
//但是不能在主线程WaitAll,因为子线程中有委托给主线程的动作,主线程WaitAll之后,子线程一直结束不了,会死锁
//可以给WaitAll和打印最终数据包一个线程
//Task.WaitAll(taskList.ToArray());//死锁
//ShowMessage()
//Task.Run(() =>
//{
// Task.WaitAll(taskList.ToArray());
// ShowMessage();
//});
}
//[min,max)
private int GetDelayRandomNumber(int min, int max)
{
Thread.Sleep(GetRandomNumber(100, 300));
return GetRandomNumber(min, max);
}
private int GetRandomNumber(int min, int max)
{
Guid guid = new Guid();
string strGuid = guid.ToString();
int seed = DateTime.Now.Millisecond;
for (int i = 0; i < strGuid.Length; i++)
{
switch (strGuid[i])
{
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
seed += 1; break;
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
seed += 2; break;
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
seed += 3; break;
case 'p':
case 'q':
case 'r':
case 's':
case 't':
seed += 4; break;
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
default:
seed += 5; break;
}
}
Random rdm = new Random(seed);
return rdm.Next(min, max);
}
private List<int> GetInterFaceNumber()
{
List<int> intList = new List<int>();
foreach (Control control in gbxResult.Controls)
{
if (control is Label)
{
Label label = (Label)control;
intList.Add(int.Parse(label.Text));
}
}
return intList;
}
private void ShowMessage()
{
string redMsg = "红球:";
string blueMsg = "蓝球:";
foreach (Control control in gbxResult.Controls)
{
if (control is Label)
{
Label label = (Label)control;
if (!label.Name.Equals("lab6"))
{
redMsg += label.Text + " ";
}
else
{
blueMsg += label.Text;
}
}
}
MessageBox.Show(redMsg + blueMsg);
}
}
}