简体   繁体   English

C#WPF多线程

[英]C# wpf multithreading

I want to generate 3 random number in threads then save it to list. 我想在线程中生成3个随机数,然后将其保存到列表中。 Here's my code 这是我的代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Threading;
    using System.IO;

    namespace Multithreading1
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            List<int> myList = new List<int>();
            int threadNumber = 0;
            int currentRecNumber = -1;

            public MainWindow()
            {
                InitializeComponent();
            }

            void ThreadHandler(int recNumber,int number)
            {
                Action action = null;
                action = () =>
                        {
                            myList[recNumber] = number;
                            ++currentRecNumber;
                            --threadNumber;
                            if (currentRecNumber < myList.Count)
                            {
                                ++threadNumber;
                                Thread t = new Thread(() => GetRandomNumber(currentRecNumber));
                                t.Start();
                            }
                            else
                                if (threadNumber == 0) //finish
                                {
                                    List<String> stringList = new List<String>();
                                    for (int i = 0; i < myList.Count;i++)
                                    {
                                        stringList.Add(myList[i].ToString());
                                    }
                                    File.WriteAllLines("C:\\Users\\Public\\Documents\\MyList.txt", stringList);
                                    System.Windows.MessageBox.Show("Finish");
                                }
                        };
                this.Dispatcher.BeginInvoke(action);
            }

            void GetRandomNumber(int recNumber)
            {
                Random rnd = new Random();
                int randomInt = rnd.Next(1, 13);
                ThreadHandler(recNumber, randomInt);
            }

            private void button1_Click(object sender, RoutedEventArgs e)
            {
                for (int i = 0; i < 20; i++)
                {
                    myList.Add(-1);
                }
                for (int i = 0; i < 3; i++)
                {
                    ++currentRecNumber;
                    ++threadNumber;
                    Thread t = new Thread(() => GetRandomNumber(currentRecNumber));
                    t.Start();
                }
            }
        }
    }

The problem are: 1. Sometimes it throw ArgumentOutOfRangeException at myList[recNumber] = number; 问题是:1.有时它在myList [recNumber] = number上抛出ArgumentOutOfRangeException; 2. If it get past (1) the resulting file still contain -1s, eg: 2.如果超过(1),则结果文件仍包含-1,例如:

-1
-1
8
6
11
-1
1
3
-1
3
3
8
8
8
8
10
10
10
10
12

Anyone know what is wrong ? 有人知道怎么了吗? Thanks in advance. 提前致谢。

Your Dispatcher.BeginInvoke will call each action on the thread the dispatcher is associated with, so you are effectively not actually running the actions on different threads. 您的Dispatcher.BeginInvoke将在与调度程序关联的线程上调用每个动作,因此实际上您实际上并未在不同的线程上运行这些动作。 It might be better to do as much as you can in the ThreadHandler method, and only make UI changes inside the BeginInvoke action. 最好在ThreadHandler方法中执行尽可能多的操作,并且只在BeginInvoke操作内更改UI。

Also in your button1_Click, you increment currentRecNumber before you start each thread, so that will cause the first few threads to skip the first few items in the list. 同样在button1_Click中,在启动每个线程之前增加currentRecNumber,这样将导致前几个线程跳过列表中的前几个项目。

You also have a major issue because you are accessing shared variables (currentRecNumber, threadNumber, and myList) from different threads, which can cause all manner of threading issues. 您还会遇到一个主要问题,因为您正在从不同的线程访问共享变量(currentRecNumber,threadNumber和myList),这可能会导致各种形式的线程问题。 You need to use some sort of synchronisation to ensure that each thread is reading and writing the correct values from these variables. 您需要使用某种类型的同步来确保每个线程正在从这些变量读取和写入正确的值。 You can use the InterlockedIncrement and InterlockedDecrement to mitigate some of these issues, but not all of them. 您可以使用InterlockedIncrement和InterlockedDecrement来缓解其中一些问题,但并非全部。

I'll also point out that creating threads is expensive, it's much better to schedule the work you want doing on thread pool threads , use a BackgroundWorker , or use one of the parallelism libraries, like the Task Parallel Library or PLINQ. 我还要指出,创建线程是昂贵的,最好安排要在线程池线程上进行的工作,使用BackgroundWorker或使用诸如任务并行库或PLINQ之类的并行库之一。

I would recommend having a read of this free ebook on threading by Joe Albahari. 我建议阅读Joe Albahari撰写的关于线程的免费电子书

Thanks Matt for the ebook. 感谢Matt提供的电子书。 It's very easy to understand. 这很容易理解。 I managed to fix my code with minor addition. 我设法通过少量添加来修复我的代码。 The key of its problem is "Lambda expressions and captured variables", so I add couple local variables to it. 问题的关键是“ Lambda表达式和捕获的变量”,因此我向其中添加了几个局部变量。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;
using System.IO;

namespace Multithreading1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        List<int> myList = new List<int>();
        int threadNumber = 0;
        int currentRecNumber = -1;

        public MainWindow()
        {
            InitializeComponent();
        }

        void ThreadHandler(int recNumber,int number)
        {
            Action action = null;
            action = () =>
                    {
                        myList[recNumber] = number;
                        ++currentRecNumber;
                        --threadNumber;
                        int localCurrentRecNumber = currentRecNumber;
                        int localThreadNumber = threadNumber;
                        if (localCurrentRecNumber < myList.Count)
                        {
                            ++threadNumber;
                            Thread t = new Thread(() => GetRandomNumber(localCurrentRecNumber));
                            t.Start();
                        }
                        else
                            if (localThreadNumber == 0) //finish
                            {
                                List<String> stringList = new List<String>();
                                for (int i = 0; i < myList.Count;i++)
                                {
                                    stringList.Add(myList[i].ToString());
                                }
                                File.WriteAllLines("C:\\Users\\Public\\Documents\\MyList.txt", stringList);
                                System.Windows.MessageBox.Show("Finish");
                            }
                    };
            this.Dispatcher.BeginInvoke(action);
        }

        void GetRandomNumber(int recNumber)
        {
            Random rnd = new Random();
            int randomInt = rnd.Next(1, 13);
            ThreadHandler(recNumber, randomInt);
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            for (int i = 0; i < 20000; i++)
            {
                myList.Add(-1);
            }
            for (int i = 0; i < 3; i++)
            {
                ++currentRecNumber;
                ++threadNumber;
                int localCurrentNumber = currentRecNumber;
                Thread t = new Thread(() => GetRandomNumber(localCurrentNumber));
                t.Start();
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM