2

现在,我正在学习多线程以及在 C# 中的使用。所以,我面临以下问题:(对不起我这么简单的问题)

假设,我们有两个名为 Producer 和 Consumer 的类。生产者任务在程序运行时产生 4 个数字,消费者任务正在消费并使用这些数字,并在程序结束时返回它们的总和。

消费者类定义:

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类体中。

感谢您的关注。

4

2 回答 2

4

我会用 替换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.

由于计时器不够精确,这种事情是完全有可能的,在第一种情况下会导致消费者读取一个过时的值,而在第二种情况下会导致消费者错过一个值。

于 2011-08-23T21:25:11.793 回答
1

你可以做类似的事情

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

注意我没有测试过这段代码!

于 2011-08-23T21:26:48.867 回答