MugenTwo
MugenTwo

Reputation: 344

Shared Memory in C# concurrency

I'm trying to solve the producer-consumer concurrency problem with semaphores in c# (I believe i solved it: I believe the semaphores solves the mutual exclusion problem and at the same time it solves the sychronization problem of the two threads).
My problem is:
I don't understand why my variable "data" passed by reference (ref) in the producer instance and in the consumer instance isn't being shared in memory.
I have only been learing C# for a couple of days and I'm pretty sure I didn't understand the keyword "ref" properly. Please bear with me.
The code:

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

namespace ProducerConsumer
{
class Program
{
    static void Main(string[] args)
    {
        Semaphore hasData = new Semaphore(0, 1);    //There is no data when the program starts
        Semaphore hasSpace = new Semaphore(1, 1);   //There is space to produce
        int data = 0;                               //the variable "data" will be a shared variable
        Producer producer = new Producer(hasData, hasSpace, ref data);
        Consumer consumer = new Consumer(hasData, hasSpace, ref data);
        Thread producerThread = new Thread(new ThreadStart(producer.Produce));
        Thread consumerThread = new Thread(new ThreadStart(consumer.Consume));
        producerThread.Start();
        consumerThread.Start();
    }
}
class Producer
{
    static Random rnd = new Random();
    private Semaphore hasData;
    private Semaphore hasSpace;
    private int data;
    public Producer(Semaphore hasData, Semaphore hasSpace, ref int data)
    {
        this.hasData = hasData;
        this.hasSpace = hasSpace;
        this.data = data;
    }
    public void Produce()
    {
        while (true)
        {
            hasSpace.WaitOne();
            this.data = rnd.Next(0, 100);
            Console.WriteLine("The producer made: " + this.data);
            Thread.Sleep(5000);
            hasData.Release();
        }
    }
}
class Consumer
{
    private Semaphore hasData;
    private Semaphore hasSpace;
    private int data;
    public Consumer(Semaphore hasData, Semaphore hasSpace, ref int data)
    {
        this.hasData = hasData;
        this.hasSpace = hasSpace;
        this.data = data;
    }
    public void Consume()
    {
        while (true)
        {
            hasData.WaitOne();
            Console.WriteLine("The consumer got: " + this.data);
            Thread.Sleep(5000);
            hasSpace.Release();
        }
    }
}
}

The Output:
enter image description here

As you can see the producer is producing in a different part of the memory and the consumer is looking at a different part of the memory.
I would also love to know how to solve this problem.
Thank you!

Upvotes: 3

Views: 1384

Answers (1)

M.kazem Akhgary
M.kazem Akhgary

Reputation: 19189

Although you pass data by ref its value is copied in data field. because int is a value type not a reference type.

You can use wrapper class to hold value inside reference type.

class RefVal<T>
{
    public T Value { get; set; }

    public RefVal(T value)
    {
        Value = value;
    }

    public override string ToString()
    {
        return Value.ToString();
    }
}

And then you have to use it instead of int like this this

RefVal<int> data = new RefVal<int>(0); //the variable "data" will be a shared variable
Producer producer = new Producer(hasData, hasSpace, data);
Consumer consumer = new Consumer(hasData, hasSpace, data);

// ...

class Producer
{
    private RefVal<int> data;

    // ...

    public Producer(Semaphore hasData, Semaphore hasSpace, RefVal<int> data)
    {
        this.hasData = hasData;
        this.hasSpace = hasSpace;
        this.data = data;
    }
    public void Produce()
    {
        while (true)
        {
            hasSpace.WaitOne();
            this.data.Value = rnd.Next(0, 100); // set value to .Value
            Console.WriteLine("The producer made: " + this.data);
            Thread.Sleep(5000);
            hasData.Release();
        }
    }
}
class Consumer
{
    private Semaphore hasData;
    private Semaphore hasSpace;
    private RefVal<int> data;
    public Consumer(Semaphore hasData, Semaphore hasSpace, RefVal<int> data)
    {
        this.hasData = hasData;
        this.hasSpace = hasSpace;
        this.data = data;
    }

    //...
}

Upvotes: 1

Related Questions