Reputation: 344
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();
}
}
}
}
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
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