patterncsharpMinor
Waiting for a lock to release with ManualResetEvent and Quartz
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
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)
{
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...
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
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.