0
Reply

Deadlock, waitone, semaphores and delegaes. Help.

Tommy Bell

Tommy Bell

May 21 2008 3:02 AM
6.1k
Hello, Im currently doing a project where i need to ensure no deadlocks can occur, or atleast be sure enough that no deadlocks can occur, and I came up with the following code based on other examples and a bag a bag of code-experienced. However, I cant seem to find information that will adaquitly explain how or indeed, even why this works.

It is a discscheduler, and I am perplexed at how I even got this working (albeit I did follow an example)

The full working code C# can be found here.
DriveScheduler

But here is what, I think are the things I am confused about.
/* request.cs */
public Request(int processId, int cylinderNumber,
            VoidMethodDelegate method)
        {
            this.rProcessId = processId;
            this.rCylinderNo = cylinderNumber;
             /* notice the semaphore (as far as I can understand, semaphore(1,1) results in a
              * semaphore that has default value as 1 and can take up one "space",
              * ->please correct me on this"
              */
            this.rProcessingLock = new Semaphore(1, 1);
            this.rMethod = method;
        }

Anyway, this rProcessingLock is used later, here
/* request.cs */
//lock for when requests are being processed
        public void WaitForProcessed()
        {
            this.rProcessingLock.WaitOne();
        }


Above we use the waitone function, as far as I can figure out, what it does is cause the thread it is called upon to wait until it receives a Set signal, but instead of using a set, the example I found and used uses a release such as this.
/* request.cs */
//release lock when done processing
        public void Done()
        {
            this.rProcessingLock.Release();
        }

However, this release is called on the semaphore.

So, question 1 remains. What does waitone really do, I've read the MSDN documentation on waitone, but it doesnt really seem clear to me how it works. Furthermore, I've read the dokumentation on how semaphores work, and I think I understand that, but if I then combine the two, Im totally lost.

Can anyone explain this to me?

The following code is used to generate request for the scheduler to process. At the bottom, a certain function is called. (request.WaitForProcessed();) Which calls the function in the request.cs file, but this is a boogle to me, the function is called on a request, where a request is

/*process.cs*/
Request request;

and is defined in the request.cs class, which is rather large. but I have included a sniplet in the bottom.

As a side question, what is up with delagates?
request = new Request(this.processId, cylinder,
                    delegate()
                    {
                        MainClass.Output(
                        "{0,-20} : Cylinder {2} received by Process {1} -> Working.", "Process", this.processId, cylinder);
                    });
where request is again defined in the request.cs as
public Request(int processId, int cylinderNumber,
            VoidMethodDelegate method)
        {
            this.rProcessId = processId;
            this.rCylinderNo = cylinderNumber;
            this.rProcessingLock = new Semaphore(1, 1);
            this.rMethod = method;
        }
but where does method come from? When it is called, delagate() is simply written, I cant seem to figure out what this does. I know delagates allows one to put whatever you want into a function and then just call that, without the delegate knowing what it does, it simply does it, but I think I misunderstand the point of them, atleast in this context.

//Function for generating the requests
        public void GenerateRequests()
        {
            Request request;
           
            // lets make sure the given request is withint the drive bounderies
            int cylinderAmount = this.pScheduler.CylindersOnDisk();
            int cylinder;
           
            int numberOfRequests = this.sRandom.Next(1, 4);
           
            for (int i = 0; i < numberOfRequests; ++i)
            {
                // Random cylinder selector
                cylinder = this.sRandom.Next(0, cylinderAmount);

                MainClass.Output("{0,-20} : Request submitted for cylinder {2} by Process {1}", "Process", this.processId, cylinder);
               
               
                /* Request generator, with added delegate
                 * for when the scheduler is processing a request
                 */
                request = new Request(this.processId, cylinder,
                    delegate()
                    {
                        MainClass.Output(
                        "{0,-20} : Cylinder {2} received by Process {1} -> Working.", "Process", this.processId, cylinder);
                    });
               
                // Notify scheduler of request
                this.pScheduler.Inquiry(request);
               
               
                /* We wait until the request is processed.
                 * Scheduler will be locked in the ProcessRequests method
                 * by using a binary semaphore, the scheduler is responsible for this
                 */
                request.WaitForProcessed();

                //output
                MainClass.Output("{0,-20} : Request on Cylinder {2} processed by Process {1}", "Process", this.processId, cylinder);
            }

/*request.cs sniplet*/
public class Request
    {
        private int rProcessId;
        private int rCylinderNo;
       
        //Semaphore used to make the process wait, without blocking. (non-blocking.)
        private Semaphore rProcessingLock;
       
        //Method for request processing
        private VoidMethodDelegate rMethod;

 ...
}

As a final note, semaphores work by
semaphore(1,1), it will allow one thread to enter and only allow another thread to enter when the previous thread has left, and decremented the value, but why does this help?
I mean, obviously only one thread can do what they need to do at a time, because a disc only has one read/write arm, but is this the reason for only allowing one thread to enter the semaphore, thus only allowing one thread to access the shared data and execute the request.

I supose I answered by own question on that last one there, but I would like your comments for it, all the same.

Anyway, I guess that is enough for one post, if anyone has any questions about this, please dont hesitate to ask, I would really like to find out what is going on here.

Regards
PS. Great community, excellent comments everytime I come here, even if only for browsing for other posts