0

我想在线程中生成 3 个随机数,然后将其保存到列表中。这是我的代码

    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();
                }
            }
        }
    }

问题是: 1. 有时它会在 myList[recNumber] = number 处抛出 ArgumentOutOfRangeException;2. 如果超过 (1),则生成的文件仍然包含 -1,例如:

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

有谁知道出了什么问题?提前致谢。

4

2 回答 2

1

您的 Dispatcher.BeginInvoke 将调用与调度程序关联的线程上的每个操作,因此您实际上并没有在不同的线程上实际运行这些操作。在 ThreadHandler 方法中尽可能多地做可能会更好,并且只在 BeginInvoke 操作中进行 UI 更改。

同样在 button1_Click 中,在启动每个线程之前增加 currentRecNumber,这样会导致前几个线程跳过列表中的前几个项目。

您还有一个主要问题,因为您正在从不同的线程访问共享变量(currentRecNumber、threadNumber 和 myList),这可能会导致各种线程问题。您需要使用某种同步来确保每个线程都从这些变量中读取和写入正确的值。您可以使用InterlockedIncrement和 InterlockedDecrement 来缓解其中一些问题,但不是全部。

我还要指出,创建线程很昂贵,最好在线程池线程上安排您想要执行的工作,使用BackgroundWorker或使用并行库之一,如任务并行库或 PLINQ。

我建议阅读Joe Albahari的这本关于线程的免费电子书。

于 2013-01-21T06:53:37.220 回答
0

感谢马特的电子书。这很容易理解。我设法通过少量添加来修复我的代码。它的问题的关键是“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();
            }
        }
    }
}
于 2013-01-22T10:34:21.860 回答