Управление отношениями потоков в C # - PullRequest
2 голосов
/ 24 августа 2011

Теперь я изучаю многопоточность и ее использование в C #. Итак, я столкнулся с проблемой, как показано ниже: (Извините за мой простой вопрос)

Предположим, что у нас есть два класса с именами Producer и Consumer. Задача Producer производит 4 числа во время выполнения программы, а задача Consumer использует и использует эти числа и возвращает их сумму в конце программы.

Определение потребительского класса:

class Consumer
{
    private HoldInteger sharedLocation;
    private Random randomSleepTime;

    public Consumer(HoldInteger shared, Random random)
    {
        sharedLocation = shared;
        randomSleepTime = random;
    }

    public void Consume()
    {
        int sum = 0;

        for (int i = 1; i <= 4; i++)
        {
            Thread.Sleep(randomSleepTime.Next(1, 3000));
            sum += sharedLocation.Buffer;
        }
    }
}

, а определение класса производителя приведено ниже:

class Producer
{
    private HoldInteger sharedLocation;
    private Random randomSleepTime;

    public Producer(HoldInteger shared, Random random)
    {
        sharedLocation = shared;
        randomSleepTime = random;
    }

    public void Produce()
    {
        for (int i = 1; i <= 4; i++)
        {
            Thread.Sleep(randomSleepTime.Next(1, 3000));
            sharedLocation.Buffer = i;
        }
    }
}

Кроме того, у нас есть HoldInteger класс, содержащий переменную Buffer, которую производитель записывает в эту переменную, а потребитель читает из нее. Я комбинирую эти классы и программирую приведенный ниже код в своем основном методе:

static void Main(string[] args)
{
   HoldInteger holdInteger = new HoldInteger();
   Random random = new Random();

   Producer producer = new Producer(holdInteger, random);

   Consumer consumer = new Consumer(holdInteger, random);

   Thread producerThread = new Thread(new ThreadStart(producer.Produce));
   producerThread.Name = "producer";

   Thread consumerThread = new Thread(new ThreadStart(consumer.Consume));
   consumerThread.Name = "consumer";

   producerThread.Start();
   consumerThread.Start();
}

Итак, мой вопрос: How can i manage this relationship With Low Memory and Time Wasting ?

Обратите внимание, что этот код управления потоками будет помещен в HoldInteger тело класса.

Спасибо за внимание.

Ответы [ 2 ]

4 голосов
/ 24 августа 2011

Я бы заменил класс HoldInteger на BlockingQueue, . Вы можете найти реализацию здесь , а для более подробной информации о причине реализации проверьте этот вопрос .Я думаю, что .NET 4.0 может иметь очередь блокировки тоже.Этот подход впоследствии значительно упростит управление:

class Producer
{
    //...

    public void Produce()
    {
        for (int i = 1; i <= 4; i++)
        {
            Thread.Sleep(randomSleepTime.Next(1, 3000));
            blockingIntQueue.Enqueue(i);
        }
    }
}

Ваш потребитель будет выглядеть следующим образом:

class Consumer
{
    //...

    public void Consume()
    {
        int value = 0;
        for (int i = 1; i <= 4; i++)
        {
            if( blockingIntQueue.TryDequeue(out value) )
            {
                sum += value;
            }
        }
    }
}

Однако, если вы хотите сохранить HoldInteger (если это какое-то требование), вы можете поместить очередь блокировки в класс HoldIntegerUnsynchronized вместо буфера (это должно быть тривиально), и вы получите тот же результат.

Примечание: при таком подходе вам больше не нужно беспокоиться о пропущенном значении или чтении устаревшего значения, потому что потоки не просыпаются точно в нужное время.Вот потенциальная проблема с использованием «буфера»:

Даже если ваш целочисленный держатель действительно безопасно обрабатывает базовый «буфер», вы все равно не гарантированы, что получите все нужные вам целые числа.Примите это во внимание:

Случай 1

Producer wakes up and writes integer.
Consumer wakes up and reads integer.

Consumer wakes up and reads integer.
Producer wakes up and writes integer.

Случай 2

Consumer wakes reads integer.
Producer wakes up and writes integer.

Producer wakes up and writes integer.
Consumer wakes up and reads integer.

Поскольку таймер недостаточно точно, такого рода вещи вполне возможны, и в первом случае это заставит потребителя прочитать устаревшее значение, а во втором случае это заставит потребителя пропустить значение.

1 голос
/ 24 августа 2011

Вы можете сделать что-то вроде

class HoldIntegerUnsynchronized {
    int buffer;
    object syncLock = new object();
    bool goodToRead = false;
    bool goodToWrite = true;

    public int Buffer {
       get {
           lock (syncLock) {
               while (!goodToWrite)
                   Monitor.Wait(syncLock);
               buffer = value;
               goodToWrite = false;
               goodToRead = true;
               Monitor.Pulse(syncLock);
           }
       }
       set {
           lock (syncLock) {
               while (!goodToRead)
                   Monitor.Wait(syncLock);
               int toReturn = buffer;
               goodToWrite = true;
               goodToRead = false;
               Monitor.Pulse(syncLock);
               return toReturn;
           }
       }
    }
}

Примечание. Я не проверял этот код!

...