1. C# / Говнокод #16253

    +130

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    61. 61
    62. 62
    63. 63
    64. 64
    65. 65
    66. 66
    67. 67
    68. 68
    69. 69
    70. 70
    71. 71
    72. 72
    73. 73
    74. 74
    75. 75
    76. 76
    77. 77
    78. 78
    79. 79
    80. 80
    81. 81
    82. 82
    83. 83
    84. 84
    85. 85
    86. 86
    87. 87
    88. 88
    89. 89
    90. 90
    91. 91
    92. 92
    93. 93
    94. 94
    class ProducerConsumer
        {
            private static Semaphore semaphore = new Semaphore(1, 2);
            static object locker = new object();
            static int product = 0;
            private static bool work = true;
            private static bool valueSet = false; // why??
    
            private static void Producer() // производитель
            {
                while (work)
                {
                    Console.WriteLine("Thread Producer start");
                    int sqr = 0;
                    semaphore.WaitOne(); // декрементируем счётчик семафора
                    for (int i = 0; i < 15; i++)
                    {
                        sqr = i * i;
                    }
                    lock (locker) // error
                    {
    
                        while (valueSet)
                        {
                            Thread.Yield();
                        }
                        product += sqr;
                        valueSet = true;
                        Console.WriteLine("Product put: " + sqr);
                        Console.WriteLine("Product now: " + product);
                    }
                    semaphore.Release(); // выход из семафора
                    Thread.Sleep(5000);
                }
            }
    
            private static void Consumer() // потребитель
            {
                const int MAX = 5;
                int[] arr = new int[MAX];
                int result = 0;
                Random rand = new Random();
    
                while (work)
                {
                    Console.WriteLine("Thread Consumer start");
                    semaphore.WaitOne(); 
                    for (int i = 0; i < 5; i++)
                    {
                        arr[i] = rand.Next(0, 1024);
                    }
                    for (int i = 0; i < 5; i++)
                    {
                        result += arr[i];
                    }
                    result /= 5;
                    while (!valueSet)
                    {
                        Thread.Yield();
                    }
                    lock (locker)
                    {
                        if (product - result > 0) // исключаем отриц.кол-ва продуктов
                        {
                            product -= result;
                            Console.WriteLine("Product get: " + result);
                        }
                        else 
                        {
                            Console.WriteLine("Product < 0");
                        }
                        valueSet = false;
                        Console.WriteLine("Product now: " + product);
                    }
                    semaphore.Release();
                    Thread.Sleep(5000);
                }
            }
    
            public static void Main()
            {
                Thread threadProducer = new Thread(Producer);
                threadProducer.Start();
    
                Thread threadConsumer = new Thread(Consumer);
                threadConsumer.Start();
    
                Thread.Sleep(5000);
    
                Console.WriteLine("Main thread start.");
                String str = System.Console.ReadLine();
                Console.ReadKey();
            } 
    }

    Корявый пример решения задачи "Producer-Consumer".

    Запостил: qstd, 29 Июня 2014

    Комментарии (23) RSS

    • cleaned
      Ответить
    • for (int i = 0; i < 15; i++)
                      {
                          sqr = i * i;
                      }

      ну ахуеть теперь
      const int MAX = 5;
                  int[] arr = new int[MAX];

      Это. я так понимаю, на будущее.
      if (product - result > 0) // исключаем отриц.кол-ва продуктов
                          {
                              product -= result;
                              Console.WriteLine("Product get: " + result);
                          }

      Гениально
      Thread.Sleep(5000);

      Sweet dreams
      Ответить
    • Очередная унылая лаба.
      Использовать не volatile булевы поля для взаимодействия разных потоков - эпик фэйл.
      Ответить
      • > эпик фэйл
        К сожалению, на x86 будет работать ;(
        Ответить
        • Чисто теоретически, компилятор может "соптимизировать" код, выкинув проверки нафик. Во многих статья по GC и управлению памятью в дотнете это обсасывается.

          Единого мнения нет. Отчасти из-за различия в спецификации ECMA и реализации Microsoft. Например, в Mono будет одно поведение, в CLR другое. Для переносимого кода лучше сразу писать "по правилам": либо с volatile, либо другие меры предпринимать.
          Ответить
          • Дык поэтому я и пишу "к сожалению" :) Вроде бы работает, а потом перестанет, при каких-нибудь условиях.
            Ответить
    • + ко всему - семафоры тут нахуй не нужны
      Ответить
    • Хуясе какой кусок говна я пропустил
      for (int i = 0; i < 5; i++)
                          {
                              arr[i] = rand.Next(0, 1024);
                          }
                          for (int i = 0; i < 5; i++)
                          {
                              result += arr[i];
                          }
                          result /= 5;
      Ответить
    • если не гоню (а я могу) вот код немного очишенный от говна - функциАнал тот же
      internal class ProducerConsumer
          {
              private static readonly object Locker = new object();
              private static int _product;
              private static bool _valueSet; // why??
              private static readonly Random Rand = new Random();
      
              private static void Producer() // производитель
              {
                  while (true)
                  {
                      lock (Locker) // error
                      {
                          Console.WriteLine("Thread Producer start");
                          int sqr = 14*14;
                          if (_valueSet) Thread.Yield();
                          _valueSet = true;
                          Console.WriteLine("Product put: " + sqr);
                          Console.WriteLine("Product now: " + (_product += sqr));
                      }
                      Thread.Sleep(5000);
                  }
              }
      
              private static void Consumer() // потребитель
              {
                  while (true)
                  {
                      if (!_valueSet) Thread.Yield();
                      lock (Locker)
                      {
                          Console.WriteLine("Thread Consumer start");
                          var result = Rand.Next(0, 1024);
                          if (_product > result) // исключаем отриц.кол-ва продуктов
                          {
                              _product -= result;
                              Console.WriteLine("Product get: " + result);
                          }
                          else Console.WriteLine("Product < 0");
                          _valueSet = false;
                          Console.WriteLine("Product now: " + _product);
                      }
                      Thread.Sleep(5000);
                  }
              }
      
              public static void Main()
              {
                  new Thread(Producer).Start();
                  new Thread(Consumer).Start();
                  Thread.Sleep(5000);
                  Console.WriteLine("Main thread start.");
                  Console.ReadKey();
              }
          }
      Ответить
      • > if (_valueSet) Thread.Yield();
        Это еще что такое. Цикл в коде ОП'а в этом плане лучше был, он хотя бы работал... А твой if один разок попробует подождать и попрет дальше. Совсем не айс.

        Тут надо юзать что-то в духе wait/notify, или как оно у вас там в .net называется, M$ же любит переименовывать. Чтобы отправитель, добавляя элемент попутно будил получателя. А получатель, забирая элемент, будил отправителя.
        Ответить
        • > или как оно у вас там в .net называется
          Monitor.Pulse и Monitor.Wait судя по всему.
          Ответить
          • Я не правил все, я так поковырялся.
            Да, оно
            Ответить
      • P.S. А вообще, оригинал тоже не работал:
        // producer
        lock (locker) { // 1. захватили лок в момент когда valueSet был true
           ...
           while (valueSet) { ... } // 2. и ждем пока valueSet станет false
           ...
        }
        // consumer
        lock (locker) { // 3. но consumer заблочится тут
           ...
           valueSet = false; // 4. и никогда не выполнит эту строчку
           ... 
        }
        // так что ждать придется вечно. deadlock.
        Ответить
      • Примерно так это должно выглядеть, если я нигде не затупил:
        // производитель
        private static void Producer() {
            Console.WriteLine("Thread Producer start");
            while (true) {
                Thread.Sleep(500); // видимость полезной работы
                int newProduct = ...; // которую мы делаем вне lock'а
                lock (locker) {
                    // ждем, пока заберут значение, если его еще не забрали
                    while (valueSet)
                        Monitor.Wait(locker);
                    // помещаем новое значение
                    product = newProduct;
                    valueSet = true;
                    // и уведомляем получателя
                    Monitor.Pulse(locker);
                }
                Console.WriteLine("Product put: " + newProduct);
            }
        }
        // получатель
        private static void Consumer() {
            Console.WriteLine("Thread Consumer start");
            while (true) {
                int newProduct;
                lock (locker) {
                    // ждем, пока появится значение, если его еще нет
                    while (!valueSet)
                        Monitor.Wait(locker);
                    // получаем новое значение
                    newProduct = product;
                    valueSet = false;
                    // и уведомляем получателя
                    Monitor.Pulse(locker);
                }
                Console.WriteLine("Got product: " + newProduct);
            }
        }
        Ответить
        • похоже на правду. Мне после футбола в лом смотреть код-с
          Ответить
          • > в лом смотреть
            Лом с отверстием?
            Ответить
            • с двумя - в одно смотрю из другого видно)
              Ответить
              • Эм, там внутри лома система зеркал?
                Ответить
                • Ду рак ты
                  Одно С моей стороны, другое - со стороны монитора. А через одно отвестие видно только лом.
                  Ашькальмэ!
                  Ответить
                  • Дык если отверстие в ломе сквозное - то оно всё-таки одно. Разве нет?

                    > А через одно отвестие видно только лом.
                    Это если оно не насквозь просверлено.
                    Ответить
                    • Понимаешь, тут нужна степень по философии науки. Вот смотри, Когда отверстие сквозное в ломе 2 отверстия если смотреть чисто на поверхность лома. А если смотреть на топологию лома, то она тоже изменилась на 1 отверстие. (несквозное отверстие с точки зрения топологии нихуя не значит, что лом, что кружка - один хуй(у меня кружка с одним креплением на ручке)) Вот тебе и дуализм сквозной дыры в природе
                      Ответить

    Добавить комментарий