2015-06-14 4 views
0

Мне нужно выполнить один метод с разными параметрами параллельно (используя C#).Использование параллельного программирования в C#

Я использую инструкции здесь:

http://www.codeproject.com/Articles/189374/The-Basics-of-Task-Parallelism-via-C

но вместо Sum(100), Sum(200), Sum(300) Я хочу, чтобы выполнить мой немного более сложный метод Oracle(JIBitArray bits, int rounds, int[] weak_bits_positions).

Фрагмент кода из Grain класса:

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace GrainApproximations 
{ 
    class Grain 
    { 
     JIBitArray NFSR; 
     JIBitArray LFSR; 

     JIBitArray key; 
     const int keysize = 128; 

     JIBitArray iv; 
     const int ivsize = 96; 

     public void Init(JIBitArray key, JIBitArray iv, int rounds) 
     { 
      this.key = key; 
      this.iv = iv; 

      NFSR = new JIBitArray(keysize); 
      LFSR = new JIBitArray(keysize); 

      /* load registers */ 
      //fill NFSR bits with key bits 
      for (int i = 0; i < keysize; ++i) 
      { 
       NFSR.Set(i, this.key.Get(i)); 
      } 

      for (int i = 0; i < ivsize; ++i) 
      { 
       LFSR.Set(i, this.iv.Get(i)); 
      } 

      //96 < i < 128 bits of LFSR - filling with 1 
      for (int i = ivsize; i < keysize; i++) 
      { 
       LFSR.Set(i, true); 
      } 

      /* do initial clockings */ 
      bool outbit; 
      bool Lbit; 
      bool Nbit; 

      for (int i = 0; i < rounds; ++i) 
      { 
       outbit = grain_keystream(); 

       Lbit = LFSR.Get(127); 
       Nbit = NFSR.Get(127); 

       LFSR.Set(127, outbit^Lbit); 
       NFSR.Set(127, outbit^Nbit); 
      } 

     } 

     private bool grain_keystream() 
     { 
      bool outbit = NFSR.Get(2)^NFSR.Get(15)^NFSR.Get(36)^ NFSR.Get(45)^NFSR.Get(64)^NFSR.Get(73)^NFSR.Get(89)^LFSR.Get(93)^(NFSR.Get(12) & LFSR.Get(8))^(LFSR.Get(13) & LFSR.Get(20))^(NFSR.Get(95) & LFSR.Get(42))^(LFSR.Get(60) & LFSR.Get(79))^(NFSR.Get(12) & NFSR.Get(95) & LFSR.Get(95)); 
      bool Nbit = LFSR.Get(0)^NFSR.Get(0)^NFSR.Get(26)^NFSR.Get(56)^NFSR.Get(91)^NFSR.Get(96)^(NFSR.Get(3) & NFSR.Get(67))^(NFSR.Get(11) & NFSR.Get(13))^(NFSR.Get(17) & NFSR.Get(18))^(NFSR.Get(27) & NFSR.Get(59))^(NFSR.Get(40) & NFSR.Get(48))^(NFSR.Get(61) & NFSR.Get(65))^(NFSR.Get(68) & NFSR.Get(84)); 
      bool Lbit = LFSR.Get(0)^LFSR.Get(7)^LFSR.Get(38)^LFSR.Get(70)^LFSR.Get(81)^LFSR.Get(96); 

      NFSR = NFSR.ShiftLeft(1); 
      LFSR = LFSR.ShiftLeft(1); 

      NFSR.Set(keysize - 1, Nbit); 
      LFSR.Set(keysize - 1, Lbit); 

      return outbit; 
     } 

     public JIBitArray Generate_Gamma_Bits(int length_in_bits) 
     { 
      JIBitArray ret = new JIBitArray(length_in_bits); 

      for (int i = 0; i < length_in_bits; i++) 
      { 
       ret.Set(i, grain_keystream()); 
      } 
      return ret; 

     } 

     public JIBitArray Oracle(JIBitArray bits, int rounds, int[] weak_bits_positions) 
     { 
      JIBitArray key_bits = bits.SubJIBitArray(0, 128); 
      JIBitArray iv_bits = bits.SubJIBitArray(128, 96); 

      JIBitArray[] L_subspace = Build_L_subspace(iv_bits, weak_bits_positions); 

      for (int i = 0; i < weak_bits_positions.Length; i++) 
      { 
       iv_bits.Set(weak_bits_positions[i], false); 
      } 

      int count = 0; 

      bool outbit = false; 
      JIBitArray gamma = new JIBitArray(1); 

      for (int i = 0; i < L_subspace.Length; i++) 
      { 
       Init(key_bits, iv_bits.Xor(L_subspace[i]), rounds); 
       outbit = Generate_Gamma_Bits(1).Get(0); 

       if (outbit) 
       { 
        count++; 
       } 

       //Console.ReadLine(); 
      } 

      Console.Write("oracle:"); 
      Console.Write(count % 2); 

      return count % 2 == 1 ? new JIBitArray(new bool[] { true }) : new JIBitArray(new bool[] { false }); 
     } 

     public JIBitArray[] Build_L_subspace(JIBitArray iv_bits, int[] weak_bits) 
     { 
      JIBitArray[] L_subspace = new JIBitArray[(int)Math.Pow((double)2, (double)weak_bits.Length)]; 
      JIBitArray[] vectors = VectorTable(weak_bits.Length); 

      for (int i = 0; i < (int)Math.Pow((double)2, (double)weak_bits.Length); i++) 
      { 
       L_subspace[i] = new JIBitArray(iv_bits.Count); 

       for (int j = 0; j < weak_bits.Length; j++) 
       { 
        L_subspace[i].Set(weak_bits[j], vectors[i].Get(j)); 
       } 
      } 

      return L_subspace; 
     } 

     //build table of all vectors of k variables 
     public static JIBitArray[] VectorTable(int k) 
     { 
      int rows = (int)Math.Pow((double)2, (double)k); 
      bool[] tmp = new bool[k]; 
      JIBitArray[] result = new JIBitArray[rows]; 
      string x = string.Empty; 
      char[] characters = new char[0]; 
      bool[] vector = new bool[0]; 

      for (int i = 0; i < rows; i++) 
      { 
       x = Convert.ToString(i, 2); 
       x = x.PadLeft(k, '0'); 
       characters = x.ToCharArray(); 
       vector = new bool[characters.Length]; 

       for (int j = 0; j < characters.Length; j++) 
       { 
        if (characters[j] == '1') 
        { 
         vector[j] = true; 
        } 
        else 
        { 
         vector[j] = false; 
        } 
       } 
       result[i] = new JIBitArray(vector); 
      } 
      return result; 
     }   
    } 
} 

JIBitArray - это модифицированная версия коллекции .NET стандартной BitArray:

http://www.codeproject.com/Articles/14430/My-BitArray-Class

В Main методе я пытаюсь выполнить:

Grain grain = new Grain(); 
Task<bool[]> parent = new Task<bool[]>(() => 
     { 
      var results = new bool[5]; // Create an array for the results 

      // This tasks creates and starts 3 child tasks 

      for (int i = 0; i < results.Length; i++) 
      { 
       new Task(() => results[i] = grain.Oracle(bits[i], rounds, weak_bits).Get(0), TaskCreationOptions.AttachedToParent).Start(); 
      } 

      // Returns a reference to the array 
      // (even though the elements may not be initialized yet) 
      return results; 
     }); 

     // When the parent and its children have 
     // run to completion, display the results 
     var cwt = parent.ContinueWith(parentTask => 
          Array.ForEach(parentTask.Result, Console.WriteLine)); 

     // Start the parent Task so it can start its children 
     parent.Start(); 

     cwt.Wait(); // For testing purposes 

где bits - это массив из 5 различных двоичных векторов JIBitArray с длиной 128 + 96 = 224 бит.

Но я получаю System.AggregateException и System.ArgumentOutOfRangeException, в то время как вычисления.

Я использую TPL, потому что мне нужно выполнить 2^20 задач с различными входными параметрами (bits имеет 2^20 элементов)

Может кто-нибудь объяснить, что это не так?

+0

Привет! Это много кода. Являются ли исключения из-за параллельной обработки? Сколько задач выполняется одновременно? Проверяются ли алгоритмы и работают ли они в непараллельной среде? Возможно, вы должны определить проблему немного лучше, чтобы получить здесь хорошие ответы ;-) – Stefan

+0

'Oracle (биты JIBitArray, int rounds, int [] weak_bits_positions)' - работает корректно в непараллельном режиме. Я вынужден использовать TPL, потому что оценка векторов 2^20 по методу «Oracle» занимает около 7 часов – storojs72

+0

Одна из проблем заключается в том, что вы не захватываете переменную цикла 'i'. К тому времени, когда выполняется внутренняя задача, 'i' уже 5. –

ответ

1

Одна из проблем заключается в том, что вы не фиксируете переменную цикла i. К моменту выполнения внутренней задачи i уже 5.

Но вы также не ожидаете результатов внутренней задачи. Почему бы не сделать внутреннюю задачу Task<bool>, чтобы вы могли получить (и дождаться) ее результат?

Также, как написано, ваша родительская задача совершенно бессмысленна, просто используйте метод, если все, что вы хотите сделать, это запустить некоторые другие задачи (у вас нет длительных вычислений там). Если вы хотите, чтобы он был полезен, он подождал бы завершения задачи «Дети», а затем вернет комбинированный результат.

Использование Parallel.ForEach сделает этот код намного проще и, скорее всего, достигнет того, что вы пытаетесь сделать.

+0

Да, я знаю о цикле 'Parallel.For'. Но ufortunatelly Он дает те же самые исключения .... – storojs72

+0

Мне кажется, что существуют некоторые ограничения на методы (средние - ограничения на операции внутри метода), которые можно поместить в конструкцию 'Parallel.For'. – storojs72

+0

При использовании 'Parallel.For' первая итерация является нормальной (вычисление первого бита является правильным), но оно прерывается на второй итерации. google не очень помогает ... – storojs72