public void WhenDone_is_called_when_lock_is_acquired() { var l = new Lock<int>(1); var first = l.Capture(new Result()); var second = l.Capture(new Result()); Assert.IsTrue(first.HasValue); Assert.IsFalse(second.HasValue); var reset = new ManualResetEvent(false); second.WhenDone( _ => reset.Set()); l.Release(); Assert.IsTrue(reset.WaitOne(TimeSpan.FromSeconds(10),true)); Assert.IsTrue(second.HasValue); l.Release(); }
public void Only_one_thread_can_acquire_the_lock_at_a_time() { var l = new Lock<int>(1); var trigger = new ManualResetEvent(false); var first = Async.Fork(() => { trigger.WaitOne(); Thread.Sleep(200); l.Capture(new Result()).Wait(); }, new Result()); Result secondInternal = null; var second = Async.Fork(() => { trigger.WaitOne(); secondInternal = l.Capture(new Result()); }, new Result()); trigger.Set(); Assert.IsFalse(first.HasValue); second.Wait(); l.Release(); Assert.IsTrue(secondInternal.HasValue); Assert.IsFalse(first.HasValue); secondInternal.Wait(); first.Wait(); Assert.IsTrue(first.HasValue); }
public override void PerformTest() { Log("Creating " + _numberOfThreads + " threads"); Thread[] threads = new Thread[_numberOfThreads]; for (int i = 0; i < _numberOfThreads; i++) { threads[i] = new Thread(Work, ThreadPriority.Normal); } _startedThreads = 0; _startedThreadsLock = new Lock(); _allThreadsStartedLock = new Lock(); _allThreadsStartedCondition = new Condition(_allThreadsStartedLock); _allThreadsStartedLock.Acquire(); Log("Starting " + _numberOfThreads + " threads"); // TODO: ParametizedThreadStart doesn't work properly for (int i = 0; i < _numberOfThreads; i++) { threads[i].Start(); } // wait for all threads to be running _allThreadsStartedCondition.Await(); _allThreadsStartedLock.Release(); Log("Waiting for all threads to finish"); _semaphore.Acquire(_numberOfThreads); // wait for all threads to finish Assert(_failedThreads + " threads failed the calculation", _failedThreads == 0); Log("All " + _numberOfThreads + " threads finished"); }
private void PerformCallback(bool timedOut) { bool lockAcquired; var spinner = new SpinWait(); // Prevent the race condition with Unregister and the previous PerformCallback call, which may still be // holding the _lock. while (!(lockAcquired = _lock.TryAcquire(0)) && !Volatile.Read(ref _unregistering)) { spinner.SpinOnce(); } // If another thread is running Unregister, no need to restart the timer or clean up if (lockAcquired) { try { if (!_unregistering) { if (_repeating) { // Allow this wait to fire again. Restart the timer before executing the callback. RestartWait(); } else { // This wait will not be fired again. Free the GC handle to allow the GC to collect this object. Debug.Assert(_gcHandle.IsAllocated); _gcHandle.Free(); } } } finally { _lock.Release(); } } _ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(_callbackHelper, timedOut); }
public void Dispose() { _lock.Release(); }
/// <summary> /// Blocks the current thread until it can enter the <see cref="SemaphoreSlim"/>, /// using a 32-bit signed integer to measure the time interval, /// while observing a <see cref="T:System.Threading.CancellationToken"/>. /// </summary> /// <param name="millisecondsTimeout">The number of milliseconds to wait, or <see cref="Timeout.Infinite"/>(-1) to /// wait indefinitely.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken"/> to observe.</param> /// <returns>true if the current thread successfully entered the <see cref="SemaphoreSlim"/>; otherwise, false.</returns> /// <exception cref="ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/> is a negative number other than -1, /// which represents an infinite time-out.</exception> /// <exception cref="System.OperationCanceledException"><paramref name="cancellationToken"/> was canceled.</exception> public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) { CheckDispose(); // Validate input if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException( "totalMilliSeconds", millisecondsTimeout, SR.SemaphoreSlim_Wait_TimeoutWrong); } cancellationToken.ThrowIfCancellationRequested(); uint startTime = 0; if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout > 0) { startTime = TimeoutHelper.GetTime(); } bool waitSuccessful = false; Task <bool> asyncWaitTask = null; bool lockTaken = false; //Register for cancellation outside of the main lock. //NOTE: Register/deregister inside the lock can deadlock as different lock acquisition orders could // occur for (1)this.m_lockObj and (2)cts.internalLock CancellationTokenRegistration cancellationTokenRegistration = cancellationToken.InternalRegisterWithoutEC(s_cancellationTokenCanceledEventHandler, this); try { // Perf: first spin wait for the count to be positive, but only up to the first planned yield. // This additional amount of spinwaiting in addition // to Monitor.Enter()’s spinwaiting has shown measurable perf gains in test scenarios. // SpinWait spin = new SpinWait(); while (m_currentCount == 0 && !spin.NextSpinWillYield) { spin.SpinOnce(); } // entering the lock and incrementing waiters must not suffer a thread-abort, else we cannot // clean up m_waitCount correctly, which may lead to deadlock due to non-woken waiters. try { } finally { m_lock.Acquire(); lockTaken = true; if (lockTaken) { m_waitCount++; } } // If there are any async waiters, for fairness we'll get in line behind // then by translating our synchronous wait into an asynchronous one that we // then block on (once we've released the lock). if (m_asyncHead != null) { Debug.Assert(m_asyncTail != null, "tail should not be null if head isn't"); asyncWaitTask = WaitAsync(millisecondsTimeout, cancellationToken); } // There are no async waiters, so we can proceed with normal synchronous waiting. else { // If the count > 0 we are good to move on. // If not, then wait if we were given allowed some wait duration OperationCanceledException oce = null; if (m_currentCount == 0) { if (millisecondsTimeout == 0) { return(false); } // Prepare for the main wait... // wait until the count become greater than zero or the timeout is expired try { waitSuccessful = WaitUntilCountOrTimeout(millisecondsTimeout, startTime, cancellationToken); } catch (OperationCanceledException e) { oce = e; } } // Now try to acquire. We prioritize acquisition over cancellation/timeout so that we don't // lose any counts when there are asynchronous waiters in the mix. Asynchronous waiters // defer to synchronous waiters in priority, which means that if it's possible an asynchronous // waiter didn't get released because a synchronous waiter was present, we need to ensure // that synchronous waiter succeeds so that they have a chance to release. Debug.Assert(!waitSuccessful || m_currentCount > 0, "If the wait was successful, there should be count available."); if (m_currentCount > 0) { waitSuccessful = true; m_currentCount--; } else if (oce != null) { throw oce; } // Exposing wait handle which is lazily initialized if needed if (m_waitHandle != null && m_currentCount == 0) { m_waitHandle.Reset(); } } } finally { // Release the lock if (lockTaken) { m_waitCount--; m_lock.Release(); } // Unregister the cancellation callback. cancellationTokenRegistration.Dispose(); } // If we had to fall back to asynchronous waiting, block on it // here now that we've released the lock, and return its // result when available. Otherwise, this was a synchronous // wait, and whether we successfully acquired the semaphore is // stored in waitSuccessful. return((asyncWaitTask != null) ? asyncWaitTask.GetAwaiter().GetResult() : waitSuccessful); }
internal readonly Codec Codec; // for writing new segments /// <summary> /// Constructs a new IndexWriter per the settings given in <code>conf</code>. /// If you want to make "live" changes to this writer instance, use /// <seealso cref="#getConfig()"/>. /// /// <p> /// <b>NOTE:</b> after ths writer is created, the given configuration instance /// cannot be passed to another writer. If you intend to do so, you should /// <seealso cref="IndexWriterConfig#clone() clone"/> it beforehand. /// </summary> /// <param name="d"> /// the index directory. The index is either created or appended /// according <code>conf.getOpenMode()</code>. </param> /// <param name="conf"> /// the configuration settings according to which IndexWriter should /// be initialized. </param> /// <exception cref="IOException"> /// if the directory cannot be read/written to, or if it does not /// exist and <code>conf.getOpenMode()</code> is /// <code>OpenMode.APPEND</code> or if there is any other low-level /// IO error </exception> public IndexWriter(Directory d, IndexWriterConfig conf) { /*if (!InstanceFieldsInitialized) { InitializeInstanceFields(); InstanceFieldsInitialized = true; }*/ readerPool = new ReaderPool(this); conf.SetIndexWriter(this); // prevent reuse by other instances Config_Renamed = new LiveIndexWriterConfig(conf); directory = d; analyzer = Config_Renamed.Analyzer; infoStream = Config_Renamed.InfoStream; mergePolicy = Config_Renamed.MergePolicy; mergePolicy.IndexWriter = this; mergeScheduler = Config_Renamed.MergeScheduler; Codec = Config_Renamed.Codec; BufferedUpdatesStream = new BufferedUpdatesStream(infoStream); PoolReaders = Config_Renamed.ReaderPooling; WriteLock = directory.MakeLock(WRITE_LOCK_NAME); if (!WriteLock.Obtain(Config_Renamed.WriteLockTimeout)) // obtain write lock { throw new LockObtainFailedException("Index locked for write: " + WriteLock); } bool success = false; try { OpenMode_e? mode = Config_Renamed.OpenMode; bool create; if (mode == OpenMode_e.CREATE) { create = true; } else if (mode == OpenMode_e.APPEND) { create = false; } else { // CREATE_OR_APPEND - create only if an index does not exist create = !DirectoryReader.IndexExists(directory); } // If index is too old, reading the segments will throw // IndexFormatTooOldException. segmentInfos = new SegmentInfos(); bool initialIndexExists = true; if (create) { // Try to read first. this is to allow create // against an index that's currently open for // searching. In this case we write the next // segments_N file with no segments: try { segmentInfos.Read(directory); segmentInfos.Clear(); } catch (IOException) { // Likely this means it's a fresh directory initialIndexExists = false; } // Record that we have a change (zero out all // segments) pending: Changed(); } else { segmentInfos.Read(directory); IndexCommit commit = Config_Renamed.IndexCommit; if (commit != null) { // Swap out all segments, but, keep metadata in // SegmentInfos, like version & generation, to // preserve write-once. this is important if // readers are open against the future commit // points. if (commit.Directory != directory) { throw new System.ArgumentException("IndexCommit's directory doesn't match my directory"); } SegmentInfos oldInfos = new SegmentInfos(); oldInfos.Read(directory, commit.SegmentsFileName); segmentInfos.Replace(oldInfos); Changed(); if (infoStream.IsEnabled("IW")) { infoStream.Message("IW", "init: loaded commit \"" + commit.SegmentsFileName + "\""); } } } RollbackSegments = segmentInfos.CreateBackupSegmentInfos(); // start with previous field numbers, but new FieldInfos GlobalFieldNumberMap = FieldNumberMap; Config_Renamed.FlushPolicy.Init(Config_Renamed); DocWriter = new DocumentsWriter(this, Config_Renamed, directory); eventQueue = DocWriter.EventQueue(); // Default deleter (for backwards compatibility) is // KeepOnlyLastCommitDeleter: lock (this) { Deleter = new IndexFileDeleter(directory, Config_Renamed.DelPolicy, segmentInfos, infoStream, this, initialIndexExists); } if (Deleter.StartingCommitDeleted) { // Deletion policy deleted the "head" commit point. // We have to mark ourself as changed so that if we // are closed w/o any further changes we write a new // segments_N file. Changed(); } if (infoStream.IsEnabled("IW")) { infoStream.Message("IW", "init: create=" + create); MessageState(); } success = true; } finally { if (!success) { if (infoStream.IsEnabled("IW")) { infoStream.Message("IW", "init: hit exception on init; releasing write lock"); } WriteLock.Release(); IOUtils.CloseWhileHandlingException(WriteLock); WriteLock = null; } } }
private void RollbackInternal() { bool success = false; if (infoStream.IsEnabled("IW")) { infoStream.Message("IW", "rollback"); } try { lock (this) { FinishMerges(false); StopMerges = true; } if (infoStream.IsEnabled("IW")) { infoStream.Message("IW", "rollback: done finish merges"); } // Must pre-close these two, in case they increment // changeCount so that we can then set it to false // before calling closeInternal mergePolicy.Dispose(); mergeScheduler.Dispose(); BufferedUpdatesStream.Clear(); DocWriter.Dispose(); // mark it as closed first to prevent subsequent indexing actions/flushes DocWriter.Abort(this); // don't sync on IW here lock (this) { if (PendingCommit != null) { PendingCommit.RollbackCommit(directory); Deleter.DecRef(PendingCommit); PendingCommit = null; Monitor.PulseAll(this); } // Don't bother saving any changes in our segmentInfos readerPool.DropAll(false); // Keep the same segmentInfos instance but replace all // of its SegmentInfo instances. this is so the next // attempt to commit using this instance of IndexWriter // will always write to a new generation ("write // once"). segmentInfos.RollbackSegmentInfos(RollbackSegments); if (infoStream.IsEnabled("IW")) { infoStream.Message("IW", "rollback: infos=" + SegString(segmentInfos.Segments)); } Debug.Assert(TestPoint("rollback before checkpoint")); // Ask deleter to locate unreferenced files & remove // them: Deleter.Checkpoint(segmentInfos, false); Deleter.Refresh(); LastCommitChangeCount = ChangeCount; Deleter.Refresh(); Deleter.Dispose(); WriteLock.Release(); IOUtils.Close(WriteLock); // release write lock WriteLock = null; Debug.Assert(DocWriter.PerThreadPool.NumDeactivatedThreadStates() == DocWriter.PerThreadPool.MaxThreadStates, "" + DocWriter.PerThreadPool.NumDeactivatedThreadStates() + " " + DocWriter.PerThreadPool.MaxThreadStates); } success = true; } catch (System.OutOfMemoryException oom) { HandleOOM(oom, "rollbackInternal"); } finally { if (!success) { // Must not hold IW's lock while closing // mergePolicy/Scheduler: this can lead to deadlock, // e.g. TestIW.testThreadInterruptDeadlock IOUtils.CloseWhileHandlingException(mergePolicy, mergeScheduler); } lock (this) { if (!success) { // we tried to be nice about it: do the minimum // don't leak a segments_N file if there is a pending commit if (PendingCommit != null) { try { PendingCommit.RollbackCommit(directory); Deleter.DecRef(PendingCommit); } catch (Exception) { } } // close all the closeables we can (but important is readerPool and writeLock to prevent leaks) if (WriteLock != null) { WriteLock.Release(); } IOUtils.CloseWhileHandlingException(readerPool, Deleter, WriteLock); WriteLock = null; } closed = true; Closing = false; } } }