多个类实例引发相同的事件

时间:2016-09-08 18:58:16

标签: c# multithreading concurrent-queue

我无法弄清楚我的C#代码有什么问题。

我试图学习如何在System.Collections.Concurrent命名空间中使用ConcurrentQueue类。

为了做到这一点,我在不同的线程中创建了同一个类的2个实例,并向构造函数传递了一个不同的Listbox控件。

我希望EventGenerator的每个类实例以随机的间隔引发事件,更新Listbox,它们是随机生成的数字传递的,并将该数字添加到ConcurrentQueue中,它也传递给构造函数。

在我的主线程中,是DeQueue由两个衍生线程对其进行EnQueue的对象的ConcurrentQueue的方法。

但我得到的是2个EnQueue列表框显示相同的数据,DeQueue列表框似乎报告了他们两个。

如果我的描述不够好,我道歉,我的代码如下,以及指向我的表单图片的链接,以防它可能更好地帮助想象我想要做的事情......

表格

public partial class Form1 : Form
{
    ConcurrentQueue<int> CQ;
    EventGenerator eventGenerator1;
    EventGenerator eventGenerator2;
    public Form1()
    {
        InitializeComponent();
        CQ = new ConcurrentQueue<int>();
        eventGenerator1 = new EventGenerator(CQ, listBox1);
        eventGenerator1.OnRandomEvent += new EventGenerator.RandomEventHandler(RandomEvent);
        eventGenerator2 = new EventGenerator(CQ, listBox2);
        eventGenerator2.OnRandomEvent += new EventGenerator.RandomEventHandler(RandomEvent);
    }

    private void RandomEvent(object sender, IncomingConnectionEventArgs e)
    {
        string s = e.Property_Int.ToString()
            + " "
            + e.Property_String;
        UpdateListbox(s, e.LB);
    }

    private void UpdateListbox(string argstring, ListBox argListBox)
    {
        if (InvokeRequired)
        {
            Invoke(new Action<string, ListBox>(UpdateListbox), new object[] { argstring, argListBox });
            return;
        }
        int n;
        bool b = false;
        //do
        //{
            b = CQ.TryDequeue(out n);
        //} while (!b);

        argListBox.Items.Add(argstring);
        argListBox.SelectedIndex = argListBox.Items.Count -1;
        listBoxDeQueue.Items.Add(n.ToString());
        listBoxDeQueue.SelectedIndex = listBoxDeQueue.Items.Count - 1;

    }

    private void button_Start_Click(object sender, EventArgs e)
    {
        Thread methodThread1 = new Thread(new ThreadStart(TheThread1));
        methodThread1.Start();
        Thread methodThread2 = new Thread(new ThreadStart(TheThread2));
        methodThread2.Start();
    }

    private void TheThread2()
    {
        eventGenerator2.Start();
    }

    private void TheThread1()
    {
        eventGenerator1.Start();

    }

    private void button_Stop_Click(object sender, EventArgs e)
    {
        eventGenerator1.Stop();
        eventGenerator2.Stop();
    }

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        eventGenerator1.Stop();
        eventGenerator2.Stop();
    }
}

IncomingConnectionEventArgs

class IncomingConnectionEventArgs : EventArgs
{
    public System.Windows.Forms.ListBox LB;
    public int Property_Int { get; set; }
    public string Property_String { get; set; }

    public IncomingConnectionEventArgs(int argInt, string argString,
        System.Windows.Forms.ListBox lb)
    {
        LB = lb;
        Property_Int = argInt;
        Property_String = argString;
    }
}

EventGenerator

class EventGenerator
{
    public delegate void RandomEventHandler(
        object sender, 
        IncomingConnectionEventArgs e);

    public event RandomEventHandler OnRandomEvent;

    public Random r = new Random();

    public ListBox listBox;

    public bool Generate = true;

    public ConcurrentQueue<int> CQ;

    public EventGenerator(ConcurrentQueue<int> argCQ, ListBox argListBox)
    {
        CQ = argCQ;
        listBox = argListBox;
    }

    public void Start()
    {
        Generate = true;
        while (Generate)
        {
            Thread.Sleep(r.Next(100, 2000));
            RandomEvent();
        }
    }

    public void Stop()
    {
        Generate = false; ;
    }

    public void RandomEvent()
    {
        if (OnRandomEvent == null)
        {
            return;
        }

        int n = r.Next(1000, 10000);
        CQ.Enqueue(n);
        IncomingConnectionEventArgs Args =
            new IncomingConnectionEventArgs(n, "", listBox);

        OnRandomEvent(this, Args);
    }
}

enter image description here

1 个答案:

答案 0 :(得分:0)

问题在于您使用Random。除非您使用Random的单个实例或以不同方式显式地为每个实例设定种子,否则调用Random.Next(...)的两个线程通常会生成相同的值。

为您的实例设定种子的更好方法是:

Random r = new Random(Guid.NewGuid().GetHashCode());