Your DataStore could have a private constructor (or protected, ask me why if didn't get it), so no one besides you can instantiate it, then in the static constructor create an instance of DataStore (this is the singleton creation)
Your CD, DVD, HDDVD, etc inherit from MediaStorage.
Your DataStore instance, will hold a List
When you want a new media to write to, you write: DataStore.Create(typeof(DVD)) this method adds a new instance of DVD to the List a new call to DataStore.Create(typeof(DVD)) would return an InvalidOperationException("DVD currently being written/read, please wait"
OR you could implement a lock mechanism, so that the thread calling this code would be locked
Let me elaborate the DataStore.Create
DataStore.Create(typeof(DVD)) would do something like:
dvdMediaMutex.Lock();
MediaStorage obj = (instanciation of media of type passed as parameter)
return obj //casting to the passed type
Don't worry with the language, we are trying to find a pattern for the problem
So assuming create, creates a lock over that media type that media type will be lock... new call to Create will be putted on hold now, because Create returns you an instance you can write to your file calling obj.Write this method could be generic being declared in the MediaStorage, MediaStorage could be abstract so that some methods are implemented and other are not...
Left to the specific class programmer to implement when you are done with the class we have to release that lock so, for that you DataStore can have a method called Dispose() that receives MediaStorage and it's role is to release the Lock so other can write when release the first thread to enter closes the lock so now the new thread is writing and the other are waiting again...
So the DataStore here implements the Singleton the Singleton almost implements the Composite but because DataStore is different type from MediaStorage it's just similar at any time if you loose the reference to your object
That would do
foreach(MediaStorage md in mediaStorages)
if(md is the_type_passed) return md;
you would call DataStore.Get(typeof(DVD))
This envolves some threading handling and type instantiation ... seems fun!
Let's see it in action, have done you a working sample.
It reflects what we have spoken earlier only! It works, and I hope it solves your problem.
Notes: I develop the code in a Class Library and then added it has reference to my Console app for testing.
The MediaStorage Class
namespace MediaLibrary
{
public abstract class MediaStorage
{
internal readonly Mutex OpenLock;
internal readonly Mutex AccessLock;
public MediaStorage() {
OpenLock = new Mutex(false, string.Format("{0} - OpenMutex",
this.GetType().FullName));
AccessLock = new Mutex(false, string.Format("{0} - OpenMutex",
this.GetType().FullName));
Data = new StringBuilder();
}
public StringBuilder Data { get; set; }
}
}
The DataStore Class
namespace MediaLibrary
{
public class DataStore
{
#region "Static Class Logic"
static DataStore instance;
public static DataStore Instance {
get {
return instance = instance ?? new DataStore();
}
}
#endregion
private readonly object openLock;
private readonly object closeLock;
Dictionary<Type, MediaStorage> mediaStorage;
private DataStore() {
openLock = new Object();
closeLock = new Object();
mediaStorage = new Dictionary<Type, MediaStorage>();
}
public MediaStorage Open(Type type) {
lock (openLock) {
MediaStorage md = null;
bool alreadyCreated = mediaStorage.TryGetValue(type.GetType(), out md);
//has never been created.
if (md == null) {
md = (MediaStorage)Activator.CreateInstance(type, true);
mediaStorage.Add(type.GetType(), md);
}
//created or pulled from the dictionary, let's try to to get the object lock.
md.OpenLock.WaitOne(-1);
//success, object obtained, don't forget everyone is blocked trying to get it,
//release as soon as possible.
return md;
}
}
public void WriteData(Type type, string data) {
//i assume the media is never removed if it's please protect this
//call with lock mechanism.
MediaStorage media = GetMedia(type);
lock (media.AccessLock) {
//simulate some delay
Thread.Sleep(1000);
media.Data.AppendFormat(
"thread:{0},data:{1}|\n", Thread.CurrentThread.ManagedThreadId, data);
}
}
public string ReadData(Type type) {
//i assume the media is never removed if it's please protect
//this call with lock mechanism.
MediaStorage media = GetMedia(type);
string data;
lock (media.AccessLock) {
//simulate some delay
Thread.Sleep(new Random(Convert.ToInt32(DateTime.Now.Ticks)).Next(2000));
data = media.Data.ToString();
}
return data;
}
private MediaStorage GetMedia(Type mediaType) {
MediaStorage md = null;
mediaStorage.TryGetValue(mediaType.GetType(), out md);
return md;
}
public void Close(MediaStorage media) {
lock (closeLock) {
if (media.OpenLock.SafeWaitHandle.IsClosed) return;
media.OpenLock.ReleaseMutex();
}
}
}
}
The CDMedia Concrete Type Class, can implement DVD, HDDVD, etc...
namespace MediaLibrary
{
public class CDMedia: MediaStorage
{
private CDMedia() { }
//anything specific of CD's
}
}
The Console App Code to Unit Test
static void Main(string[] args) {
DataStore storage = DataStore.Instance;
Console.WriteLine("Main program waking up...\n\n");
Console.WriteLine("Launching Thread of Writers...");
Thread writters1 = new Thread(new ThreadStart(delegate() {
Console.WriteLine("Writters thread, openning media...\n");
CDMedia cd = (CDMedia)storage.Open(typeof(CDMedia));
Thread writer1 = new Thread(new ThreadStart(delegate() {
Console.WriteLine("Writters thread, writer 1 writting...");
//safe write
storage.WriteData(typeof(CDMedia), "DataWriter 1, I love to write data all day long, specially on sunny days...");
}));
Thread writer2 = new Thread(new ThreadStart(delegate() {
Console.WriteLine("Writters thread, writer 2 writting...");
//safe write
storage.WriteData(typeof(CDMedia), "DataWriter 2, I love to write data all day long, specially on windy days...");
}));
Thread writer3 = new Thread(new ThreadStart(delegate() {
Console.WriteLine("Writters thread, writer 3 writting...");
//safe write
storage.WriteData(typeof(CDMedia), "DataWriter 3, I love to write data all day long, specially on rainy days...");
}));
writer1.Start();
writer2.Start();
writer3.Start();
writer1.Join();
writer2.Join();
writer3.Join();
//all done release media
Console.WriteLine("\nWritters thread, ended, releasing resource\n");
storage.Close(cd);
}));
Console.WriteLine("Launching Thread of Writers 2...");
Thread writters2 = new Thread(new ThreadStart(delegate() {
Console.WriteLine("Writters thread, openning media...\n");
CDMedia cd = (CDMedia)storage.Open(typeof(CDMedia));
Thread writer1 = new Thread(new ThreadStart(delegate() {
Console.WriteLine("Writters thread, writer 4 writting...");
//safe write
storage.WriteData(typeof(CDMedia), "DataWriter 4, I love to write data all day long, specially on sunny days...");
}));
Thread writer2 = new Thread(new ThreadStart(delegate() {
Console.WriteLine("Writters thread, writer 5 writting...");
//safe write
storage.WriteData(typeof(CDMedia), "DataWriter 5, I love to write data all day long, specially on windy days...");
}));
Thread writer3 = new Thread(new ThreadStart(delegate() {
Console.WriteLine("Writters thread, writer 6 writting...");
//safe write
storage.WriteData(typeof(CDMedia), "DataWriter 6, I love to write data all day long, specially on rainy days...");
}));
writer1.Start();
writer2.Start();
writer3.Start();
writer1.Join();
writer2.Join();
writer3.Join();
//all done release media
Console.WriteLine("\nWritters thread, ended, releasing resource\n");
storage.Close(cd);
}));
writters1.Start();
writters2.Start();
writters1.Join();
writters2.Join();
Console.WriteLine("Main program, let's check CDMedia Content shall we?!\n");
CDMedia cdMedia = (CDMedia)storage.Open(typeof(CDMedia));
Console.WriteLine("CD content: \n" + cdMedia.Data.ToString() + "\n");
storage.Close(cdMedia);
Console.WriteLine("The End!");
Console.ReadKey();
}
Regards.