Ждем блокировки с событие manualresetevent и кварца


Выполнение: в ожидании блокировки с резьбой.Сон()?

Я нашел время я пытался переписать мой WaitForLock-способ использовать Quartz.NET планировщик, который я использую в течение нескольких месяцев для других вещей. Это немного сложнее, но по крайней мере он сейчас не попадает в страшный поток.Сон() полностью, который является большим шагом для меня.

Хотя, сейчас было бы слишком сложно.

/// <summary>Waits for the lock to be released within the given timeout.</summary>
/// <param name="lockName">The name of the lock.</param>
/// <param name="timeout">The timeout in seconds.</param>
/// <returns>True if the Lock was released.</returns>
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);
}

/// <summary>Create and schedule the job to wait for the lock.</summary>
/// <param name="lockName">The name of the lock.</param>
/// <param name="repeat">The times it shall repeat.</param>
/// <param name="reset">The ManualResetEvent to report on.</param>
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)
    {
        ILocker locker = (ILocker)context.JobDetail.JobDataMap.Get("Locker");
        ManualResetEvent reset = (ManualResetEvent)context.JobDetail.JobDataMap.Get("reset");
        String lockName = (String)context.JobDetail.JobDataMap.Get("LockName");

        if(!locker.IsLocked(lockName))
        {
            context.Scheduler.UndscheduleJob(context.Trigger.Name, context.Trigger.Group);
            reset.Set();
        }
    }
}

Я не совсем уверен, если я что-то улучшилось, или создали чудовище, которое пожрет меня. Ваши мысли по этому поводу?

Обновление: так как я все еще есть комментарий от Брайана Райхле в мои уши, я двинулся на ожидание и получение блокировки одной атомарной операции.

Также запланированы работы был изменен, чтобы напрямую получить блокировку. Да, я знаю, что он пытается заблокировать его дважды на успех (я просто понял, что, но не вижу способа, чтобы изменить это).

/// <summary>Tries to acquire the Lock within the given timeout.</summary>
/// <param name="lockName">The name of the lock.</param>
/// <param name="timeout">The timeout in seconds.</param>
/// <returns>True if the Lock could be acquired.</returns>
public bool WaitForLock(String lockName, Int32 timeout)
{
    // boolean ILocker.Lock(String lockName)
    // Returns true if it was able to engage the lock.
    if(locker.Lock(lockName))
        return true; // Easy way out

    using(ManualResetEvent reset = new ManualResetEvent(False)
    {
        ScheduleLockWaiter(lockName, timeout, reset);
        reset.WaitOne(timeout * 1000, false);
    }

    return locker.Lock(lockName);
}

// Further down the road, our Job-Class
public class LockJob : IJob
{
    public void Execute(JobExecutionContext context)
    {
        ILocker locker = (ILocker)context.JobDetail.JobDataMap.Get("Locker");
        ManualResetEvent reset = (ManualResetEvent)context.JobDetail.JobDataMap.Get("reset");
        String lockName = (String)context.JobDetail.JobDataMap.Get("LockName");

        if(locker.Lock(lockName))
        {
            context.Scheduler.UndscheduleJob(context.Trigger.Name, context.Trigger.Group);
            reset.Set();
        }
    }
}


2446
7
задан 29 июня 2011 в 10:06 Источник Поделиться
Комментарии
1 ответ

Я прочитал ваш изначальный вопрос и эту и не видеть, как через событие manualresetevent/кварц добавляет ничего ценного. Насколько я понимаю, весь смысл сна, только чтобы избежать опроса слишком часто БД.

Вот некоторые псевдокод...

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
}
}

Это то, что вы пытаетесь достичь?

НБ. Это просто очень грубый набросок ... возможно, вы захотите добавить некоторые владельца замка и проверить его в

5
ответ дан 1 октября 2012 в 07:10 Источник Поделиться