现在的位置: 首页 > 综合 > 正文

一个用双信号灯同步机制,协调两个后台线程的例子。

2013年12月07日 ⁄ 综合 ⁄ 共 2349字 ⁄ 字号 评论关闭

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WindowsFormsApplication2
{
    /// <summary>
    /// 本例子通过双信号灯同步机制,演示两个后台线程如何同步工作,在窗口中打印出 "HelloX World!" 序列。
    /// 具体功能如下:(注意:程序中凡有注释的语句都比较关键,勿遗漏。)
    ///
    ///  1、线程1产生数据, 通过类变量简单地传递数据给线程2,而线程2则接收和处理数据;
    ///  2、线程1、线程2不会出现失步,即:数据不重复处理、不漏处理、处理结果不重复显示、也不漏显示;
    ///  3、线程2在后台如何跨线程访问 UI 元素;
    /// 
    /// 根据本文原理,读者完全可以对此类模式进行封装,实现更多个后台线程任务的同步工作能力。
    /// 如有任何疑问,欢迎邮件(或MSN):appframework@hotmail.com,本人每周末会抽空答复。
    /// </summary>
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Thread t1 = new Thread(ThreadStart1);
            t1.IsBackground = true; // 放在后台运行,在主线程退出时才不会阻塞进程退出。

            Thread t2 = new Thread(ThreadStart2);
            t2.IsBackground = true; // 放在后台运行,在主线程退出时才不会阻塞进程退出。

            // 通过双信号灯同步机制,以下两个工作线程的启动先后顺序可以随意。
            t1.Start();
            t2.Start();
        }

        /// <summary>
        /// 自定义一个通用代理,供后续所有需要跨线程访问 UI 的地方使用。
        /// </summary>
        delegate void CrossThreadUIDelegate();

        private string _syncBuffer = string.Empty;

        /// <summary>
        /// 在任务1完成时发出信号
        /// </summary>
        private AutoResetEvent _syncEvent1 = new AutoResetEvent(false);

        /// <summary>
        /// 在任务2完成时发出信号
        /// </summary>
        private AutoResetEvent _syncEvent2 = new AutoResetEvent(false);

        public void ThreadStart1()
        {
            int i = 0;
            while (true)
            {
                Thread.Sleep(1000);

                _syncBuffer = "Hello" + (i++) + " "; // 设置数据
                _syncEvent1.Set(); // 任务1完成了,设置标志给任务2放行
                _syncEvent2.WaitOne(); // 等待任务2完成信号
            }
        }

        /// <summary>
        /// 后台线程,负责接收、处理和显示数据
        /// </summary>
        public void ThreadStart2()
        {
            while (true)
            {
                CrossThreadUIDelegate d = delegate()
                {
                    textBox1.Text += _syncBuffer + "World!/r/n";
                };

                _syncEvent1.WaitOne(); // 等待任务1完成信号

                try
                {
                    textBox1.Invoke(d); // 跨线程访问 UI 元素
                }
                catch // 防止异常退出导致线程1无限等待
                {
                }

                _syncEvent2.Set(); // 任务2完成,设置标志给任务1放行
            }
        }
    }
}

抱歉!评论已关闭.