zoukankan      html  css  js  c++  java
  • EventWaitHandle使用方法小记

      在项目制作的过程中,由于程序需要处理的数据量比较大,所以采用异步的方式来进行,也就是利用委托的BeginInvoke方法和EndInvoke方法来进行。效果很不错,达到了预期。但是由于程序在运行的时候,需要先加载数据,数据加载完成以后,然后进行数据比对差异,并对有差异的数据进行着色处理,在这儿,问题就来了。

      什么问题呢?我们知道,当利用异步的时候,实际上系统会自动为我们创建前后台交互线程,那么这个数据加载和差异着色就运行在了这样的线程之上,所以二者的运行先后顺序是不可知的,事实上,程序中着色的混乱也验证了这一点:那就是我虽然原本想让数据加载完成后在进行代码差异着色,可是实际运行的时候发现,数据是边加载边着色的,这也归咎到如何将多个线程合并为一个并且按序运行的问题。

      数据加载的异步代码如下:

     //start to perform async action
    private void BeginDealDataInformation(ListView listview,string fileName,EnumX enums)
    {
    DealDataInformationDelegateAsync dAsync = new DealDataInformationDelegateAsync(DealDataInformation);
    IAsyncResult iar = dAsync.BeginInvoke(listview,fileName,enums,new AsyncCallback(EndDealDataInformation),dAsync);

    if ((enumThis = enums) == EnumX.leftSide) tsStatus.Text = "正在加载左边文件的数据,请等待...";
    if ((enumThis = enums) == EnumX.rightSide) tsStatus.Text = "正在加载右边文件的数据,请等待...";
    }

    //returen the async running result
    private void EndDealDataInformation(IAsyncResult iar)
    {
    UIThread.UIInvoke(this.toolStrip1, delegate
    {
    if (enumThis == EnumX.leftSide) tsStatus.Text = "左边数据加载完毕,请继续下面操作...";
    if (enumThis == EnumX.rightSide) tsStatus.Text = "右边数据加载完毕,请继续下面操作...";
    });
    DealDataInformationDelegateAsync dAsync = (DealDataInformationDelegateAsync)iar.AsyncState;
    dAsync.EndInvoke(iar);
    }


    //this is a function that takes a lot of time to run, need to use async action to perform it.
    private void DealDataInformation(ListView listview,string fileName,EnumX enums)
    {
    //myHandle.Reset();//让其他需要等待的线程阻塞
    if (ColumnHeaderCollection == null) throw new Exception("文件内容为空或者不以逗号分隔!!!");

    int columnCount = ColumnHeaderCollection.Length;
    for (int i = 0; i < columnCount; i++)
    {
    ColumnHeader header = new ColumnHeader();
    header.Text = ColumnHeaderCollection[i];
    header.TextAlign = HorizontalAlignment.Left;

    UIThread.UIInvoke(listview, delegate {
    listview.Columns.Add(header);
    });
    }

    int tryResult;

    using (StreamReader sr = new StreamReader(fileName, Encoding.Default))
    {
    string result;
    while ((result = sr.ReadLine()) != null)
    {
    string[] _result = result.Split(',');
    ListViewItem lvi = new ListViewItem(_result[0]);

    if (Int32.TryParse(_result[0], out tryResult))
    {
    if (enums == EnumX.leftSide) DataCache.cacheRecordListOne.Add(Int32.Parse(_result[0])); //cache the record
    if (enums == EnumX.rightSide) DataCache.cacheRecordListTwo.Add(Int32.Parse(_result[0])); //cache the record
    }

    for (int j = 1; j < _result.Length; j++)
    {
    lvi.SubItems.Add(_result[j]);
    }

    //add items
    UIThread.UIInvoke(listview, delegate
    {
    listview.Items.Add(lvi);
    if (enums == EnumX.leftSide) DataCache.listItemLeft.Add(lvi);
    if (enums == EnumX.rightSide) DataCache.listItemRight.Add(lvi);
    });
    }
    }

    //remove the first item(commonly, it's a header)
    UIThread.UIInvoke(listview, delegate
    {
    listview.Items.RemoveAt(0);
    //DataCache.listItemLeft.RemoveAt(0);
    //DataCache.listItemRight.RemoveAt(0);
    });
    //myHandle.Set(); //允许其他等待的线程运行
    }

     这里我们可以看到需要传入3个参数。

    差异着色的异步处理方法如下:

     private void ColorTheResultAsync(EnumX enums,ListView listview)
    {
    //myHandle.WaitOne(); //处于等待状态,直到收到Set的信号
    CommonUntil commonUntil = new CommonUntil();
    List<int> existList=null;
    List<int> nonExistList = null;

    if (enums == EnumX.leftSide)
    {
    existList = commonUntil.ReturnComparisonResult(DataCache.cacheRecordListOne, DataCache.cacheRecordListTwo)[0];
    nonExistList=commonUntil.ReturnComparisonResult(DataCache.cacheRecordListOne, DataCache.cacheRecordListTwo)[1];

    listPartOne[0] = existList;
    listPartOne[1] = nonExistList;
    }

    if (enums == EnumX.rightSide)
    {

    existList = commonUntil.ReturnComparisonResult(DataCache.cacheRecordListTwo, DataCache.cacheRecordListOne)[0];
    nonExistList = commonUntil.ReturnComparisonResult(DataCache.cacheRecordListTwo, DataCache.cacheRecordListOne)[1];

    listPartTwo[0] = existList;
    listPartTwo[1] = nonExistList;
    }

    int __result;
    UIThread.UIInvoke(listview, delegate
    {

    foreach (ListViewItem lvi in listview.Items)
    {

    if (Int32.TryParse(lvi.Text, out __result))
    {
    if (existList.Contains(Int32.Parse(lvi.Text)))
    {
    if (enums == EnumX.leftSide) lvi.BackColor = Color.Wheat;
    if (enums == EnumX.rightSide) lvi.BackColor = Color.YellowGreen;
    }
    }
    }
    listview.Invalidate();
    });
    }

    private void BeginColorTheResultAsync(EnumX enums,ListView listview)
    {
    ColorTheResultDelegateAsync colorTheResultAsync = new ColorTheResultDelegateAsync(ColorTheResultAsync);
    IAsyncResult iar = colorTheResultAsync.BeginInvoke(enums, listview, new AsyncCallback(EndColorTheResultAsync),colorTheResultAsync);

    tsStatus.Text = "正在着色中,请等待...";
    }

    private void EndColorTheResultAsync(IAsyncResult iar)
    {
    tsStatus.Text = "着色完毕,请检测...";
    ColorTheResultDelegateAsync colorTheResultAsync = (ColorTheResultDelegateAsync)iar.AsyncState;
    colorTheResultAsync.EndInvoke(iar);
    }

      可以看到需要两个参数来运行。

      本来想直接开两个线程,然后利用Thread的join方法将线程合并为一个,然后顺序运行,以达到需要的效果,但是需要传至少两个参数进去,查看了一下ParameterizedThreadStart,发现结尾只能带一个object类型的参数,但是由于我这里传入的多于一个(虽然可以将这些参数用类包装起来,当作object传过去,但是那样确实比较麻烦,我还不确定这个程序需要不需要扩展呢),于是只要寻找别的方法。

      在查资料的过程中,我突然想到一个类:EventWaitHandle,也就是本文的主角。

      这个类通过在线程之间设置信号量,可以非常方便的控制线程运行的顺序。具体代码如下:

      首先全局申明:

     EventWaitHandle myHandle = new EventWaitHandle(false, EventResetMode.ManualReset);  //将信号状态置为非终止,使用手动重置

      其次在大数据处理的函数开始加上

     myHandle.Reset();//让其他需要等待的线程阻塞

      末尾加上:

    myHandle.Set();  //允许其他等待的线程运行

      具体形式如下:

     private void DealDataInformation(ListView listview,string fileName,EnumX enums)
    {
    myHandle.Reset();//让其他需要等待的线程阻塞
        ....................
    myHandle.Set(); //允许其他等待的线程运行
    }

      其中Reset方法可以让本函数进行处理,而让其他在线程上的未接收到信号量的函数进入阻塞状态,而Set方法则是释放信号量,以便通知阻塞线程当前处理结束,可以继续进行。

      那么怎么控制哪些函数需要阻塞呢? 很简单:

      直接在函数的入口处加上:

    private void ColorTheResultAsync(EnumX enums,ListView listview)
    {
    myHandle.WaitOne(); //处于等待状态,直到收到Set的信号
    .........
    }

    就表明只有当承载DealDataInformation函数的线程运行完毕,承载ColorTheResultAsync函数的线程才可以开始运行,这样就做到了顺序运行。

  • 相关阅读:
    模板 无源汇上下界可行流 loj115
    ICPC2018JiaozuoE Resistors in Parallel 高精度 数论
    hdu 2255 奔小康赚大钱 最佳匹配 KM算法
    ICPC2018Beijing 现场赛D Frog and Portal 构造
    codeforce 1175E Minimal Segment Cover ST表 倍增思想
    ICPC2018Jiaozuo 现场赛H Can You Solve the Harder Problem? 后缀数组 树上差分 ST表 口胡题解
    luogu P1966 火柴排队 树状数组 逆序对 离散化
    luogu P1970 花匠 贪心
    luogu P1967 货车运输 最大生成树 倍增LCA
    luogu P1315 观光公交 贪心
  • 原文地址:https://www.cnblogs.com/scy251147/p/2296249.html
Copyright © 2011-2022 走看看