网上找的,做个笔记记录一下。
有这么一个需求,就是巡检多台服务器是否都在线,点击巡检按钮后,按行读取DataGridView中的数据,并启行线程执行,这时会存在多个线程同时运行,但是什么时候给出用户提醒,说都巡检完成了呢,需要用到一个线程状态的检测。
最后的效果是这样子的,多个线程对表格按行进行服务器的巡检,只有等所有的巡检线都结束后,等待线程才会弹出一个巡检完毕的提示框,在巡检的过程中,不会卡主界面。
1、新建一个类,用于处理线程状态的计数,用于解决EventWaitHandle时线程不能超过64个的问题
public class MutipleThreadResetEvent : IDisposable
{
private readonly ManualResetEvent done;
private readonly int total;
private long current;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="total">需要等待执行的线程总数</param>
public MutipleThreadResetEvent(int total)
{
this.total = total;
current = total;
done = new ManualResetEvent(false);
}
/// <summary>
/// 唤醒一个等待的线程
/// </summary>
public void SetOne()
{
// Interlocked 原子操作类 ,此处将计数器减1
if (Interlocked.Decrement(ref current) == 0)
{
//当所以等待线程执行完毕时,唤醒等待的线程
done.Set();
}
}
/// <summary>
/// 等待所以线程执行完毕
/// </summary>
public void WaitAll()
{
done.WaitOne();
}
/// <summary>
/// 释放对象占用的空间
/// </summary>
public void Dispose()
{
((IDisposable)done).Dispose();
}
}
2、定义一个结构体,用于存放线程需要的参数和MutipleThreadResetEvent
struct webInfo
{
public int xh;
public string lx;
public string path;
public object mre;
//public ManualResetEvent mre;
}
3、在DataGridView中使用
int num = DG_show.RowCount - 1;
for (int i = 0; i < DG_show.RowCount - 1; i++)
{
DG_show.Rows[i].Cells["验证结果"].Value = "";
DG_show.Rows[i].DefaultCellStyle.BackColor = Color.White;
}
//开始进行验证
//manualEvents.Clear(); //以前的代码,可以删除
PR1.Maximum = num;
PR1.Minimum = 0;
var countdown = new MutipleThreadResetEvent(num);
webInfo info1;
ThreadPool.SetMaxThreads(5,5); //设置最大的线程数量
for (int i = 0; i < DG_show.RowCount - 1; i++)
{
//ManualResetEvent mre = new ManualResetEvent(false);
//manualEvents.Add(mre);
info1.xh = i;
//info1.mre = mre;
info1.mre = countdown;
info1.lx = DG_show.Rows[i].Cells["方式"].Value.ToString().Trim();
info1.path = DG_show.Rows[i].Cells["地址"].Value.ToString().Trim();
//Thread thread1 = new Thread(new ParameterizedThreadStart(CheckResult));
//thread1.Start(info1);
//进行巡检的线程
ThreadPool.QueueUserWorkItem(CheckResult, info1);
}
//等待所有巡检线程执行完毕的线程
Thread th1 = new Thread(new ParameterizedThreadStart(WaitThreadEnd));
th1.Start(countdown);
CheckResult和WaitThreadEnd就是具体的业务处理
4、巡检线程和等待线程中的写法
巡检线程
private void CheckResult(object info)
{
webInfo web = (webInfo)info;
//... ...省略掉具体的业务过程
MutipleThreadResetEvent countdown = web.mre as MutipleThreadResetEvent;
countdown.SetOne();
}
等待巡检线程执行完毕的等待线程,其中执行一些启用主ui界面控件显示,进度条控件,按钮控件等操作,但是弹出的对话框有点问题,是在线程中弹出的,用户可能关注不到它。
public void WaitThreadEnd(object obj)
{
MutipleThreadResetEvent countdown = obj as MutipleThreadResetEvent;
countdown.WaitAll();
MessageBox.Show("服务器可访问性验证已经完成,验证通过" + js1.ToString() + "个,验证失败" + js2.ToString() + "个!", "验证提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
if (btn_start.InvokeRequired)
{
this.BeginInvoke(new Action<bool>((x) => { btn_start.Enabled = x; PR1.Visible = false; }), true);
}
}
运行起来后效果还不错,对于我们这种小白用户可以解决大部分的问题了。