2013-01-21 3 views
0

Je veux générer 3 nombres aléatoires dans les threads puis les enregistrer dans la liste. Voici mon codeC# wpf multithreading

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

Le problème est: 1. Parfois, il jette ArgumentOutOfRangeException à maListe [recnumber] = nombre; 2. Si elle aller au-delà (1) le fichier résultant contient encore -1s, par exemple:

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

Quelqu'un sait ce qui ne va pas? Merci d'avance.

Répondre

1

Votre Dispatcher.BeginInvoke appelle chaque action sur le thread auquel le répartiteur est associé, de sorte que vous n'exécutez pas réellement les actions sur des threads différents. Il serait peut-être préférable d'en faire autant que possible dans la méthode ThreadHandler et de ne modifier l'interface que dans l'action BeginInvoke.

Toujours dans votre button1_Click, vous incrémentez currentRecNumber avant de démarrer chaque thread, de sorte que les premiers threads ignorent les premiers éléments de la liste.

Vous avez également un problème majeur car vous accédez à des variables partagées (currentRecNumber, threadNumber et myList) à partir de threads différents, ce qui peut provoquer toutes sortes de problèmes de thread. Vous devez utiliser une sorte de synchronisation pour vous assurer que chaque thread lit et écrit les valeurs correctes à partir de ces variables. Vous pouvez utiliser le InterlockedIncrement et InterlockedDecrement pour atténuer certains de ces problèmes, mais pas tous. Je signale également que la création de threads est coûteuse, il vaut mieux planifier le travail que vous voulez faire sur thread pool threads, utiliser un BackgroundWorker, ou utiliser l'une des bibliothèques de parallélisme, comme la Task Parallel Library ou PLINQ.

Je recommande d'avoir une lecture de this free ebook sur le filetage par Joe Albahari.

+0

Je pensais que this.Dispatcher.BeginInvoke (action) exécutera une action en série sur le thread principal. Y-a-t-il un moyen de faire ça ? – Irwan

+0

quelque chose comme PostMessage – Irwan

+0

Oui. L'action est exécutée par votre thread principal uniquement. –

0

Merci Matt pour l'ebook. C'est très facile à comprendre. J'ai réussi à corriger mon code avec un ajout mineur. La clé de son problème est "expressions lambda et les variables capturées", donc j'ajoute quelques variables locales à lui.

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