HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Waiting for a lock to release with ManualResetEvent and Quartz

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
waitingwithmanualreseteventreleaseforandquartzlock

Problem

Follow-up to: Waiting for a lock to release with Thread.Sleep()?

I've found the time I tried to rewrite my WaitForLock-Method to utilize the Quartz.NET Scheduler which I've been using for some months now for other stuff. It got a little bit more complicated but at least it now misses the dreaded Thread.Sleep() completely, which is a big improvement for me.

Though, it might now be too complicated.

```
/// Waits for the lock to be released within the given timeout.
/// The name of the lock.
/// The timeout in seconds.
/// True if the Lock was released.
public bool WaitForLock(String lockName, Int32 timeout)
{
// IsLocked(String) does query the database for the status
if(!locker.IsLocked(lockName))
return true;

using(ManualResetEvent reset = new ManualResetEvent(False)
{
ScheduleLockWaiter(lockName, timeout, reset);
reset.WaitOne(timeout * 1000);
// WARNING: This overload is only available in: 4, 3.5 SP1, 3.0 SP2, 2.0 SP2
// I spend a half day trying to figure that out.
}

return !locker.IsLocked(lockName);
}

/// Create and schedule the job to wait for the lock.
/// The name of the lock.
/// The times it shall repeat.
/// The ManualResetEvent to report on.
private void ScheduleLockWaiter(String lockName, Int32 repeat, ManualResetEvent reset)
{
// Utilizing Quartz.NET

String name = "LockJob_" + lockName;
Trigger trigger = TriggerUtils.MakeSecondlyTrigger("LockTrigger_" + lockName, 1, repeat - 1);

JobDetail job = new JobDetail(name, _lockJobGroup, typeof(LockJob));
job.JobDataMap.Add("Locker", _locker);
job.JobDataMap.Add("Reset", reset);
job.JobDataMap.Add("LockName", lockName);

if(_scheduler.GetJobDetail(name, _lockJobGroup) != null)
_scheduler.UnscheduleJob(name, _lockJobGroup);

_scheduler.ScheduleJob(job, trigger);
}

// Further down the road, our Job-Class
public class LockJob : IJob
{
public void Execute(JobExecutionContext context)
{

Solution

I read your original question and this one and don't see how using ManualResetEvent/Quartz adds anything valuable. As far as I understand the whole point of sleeping is just to avoid polling the DB too frequently.

Here some pseudocode...

create table lock (name varchar(50) primary key)

bool tryLockNonBlocking(name_to_lock) {
    try {
        insert into lock (name) values (:name_to_lock)
        commit
        return true
    } catch(UniqueConstraintViolation) {
        return false
    }    
}

void releaseLock(name_to_release) {
    delete from lock where name = :name_to_release
    commit
}

final POLL_PERIOD = 100 // msecs

bool tryLockWithTimeout(name_to_lock, timeoutSeconds) {
    waitTimeMS = timeoutSeconds * 1000
    while(true) {
        boolean gotLock = tryLockNonBlocking()
        if(gotLock)
            return true
        waitTime -= POLL_PERIOD
        if(waitTime > 0) 
            Sleep(POLL_PERIOD)
        else
            return false
    }
}


Is that what you are trying to achieve?

NB. This is just a very rough draft ... you might want to add some lock owner and check it in

Code Snippets

create table lock (name varchar(50) primary key)


bool tryLockNonBlocking(name_to_lock) {
    try {
        insert into lock (name) values (:name_to_lock)
        commit
        return true
    } catch(UniqueConstraintViolation) {
        return false
    }    
}

void releaseLock(name_to_release) {
    delete from lock where name = :name_to_release
    commit
}


final POLL_PERIOD = 100 // msecs

bool tryLockWithTimeout(name_to_lock, timeoutSeconds) {
    waitTimeMS = timeoutSeconds * 1000
    while(true) {
        boolean gotLock = tryLockNonBlocking()
        if(gotLock)
            return true
        waitTime -= POLL_PERIOD
        if(waitTime > 0) 
            Sleep(POLL_PERIOD)
        else
            return false
    }
}

Context

StackExchange Code Review Q#3197, answer score: 5

Revisions (0)

No revisions yet.