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函数的线程才可以开始运行,这样就做到了顺序运行。

  • 相关阅读:
    VMware虚拟机安装
    代码搜索的终极武器Ag
    模糊搜索神器fzf
    Python:json、xml、字典各种转换
    03-azkaban安装部署
    linux下环境变量PATH设置错误的补救
    01-编译azkaban
    VMware安装CentOS7
    PS(二)
    等待公交车的时间
  • 原文地址:https://www.cnblogs.com/scy251147/p/2296249.html
Copyright © 2011-2022 走看看