private IAsyncResult LoadAsync(VolumeLoadProgressCallback onProgress = null, VolumeLoadCompletionCallback onComplete = null, VolumeLoadErrorCallback onError = null) { AssertNotDisposed(); if (_volumeReference != null) { return(null); } if (_backgroundLoadMethod != null) { return(_backgroundLoadMethodAsyncResult); } lock (_backgroundLoadSyncRoot) { if (_volumeReference != null) { return(null); } if (_backgroundLoadMethod != null) { return(_backgroundLoadMethodAsyncResult); } _backgroundLoadMethod = () => { try { LoadCore(onProgress); if (onComplete != null) { onComplete.Invoke(this); } } catch (Exception ex) { if (onError != null) { onError.Invoke(this, ex); } else { Platform.Log(LogLevel.Debug, ex, "Unhandled exception thrown in asynchronous volume loader"); } } }; return(_backgroundLoadMethodAsyncResult = _backgroundLoadMethod.BeginInvoke(ar => { _backgroundLoadMethod.EndInvoke(ar); _backgroundLoadMethod = null; _backgroundLoadMethodAsyncResult = null; }, null)); } }
private Volume LoadCore(VolumeLoadProgressCallback callback) { // TODO (CR Apr 2013): Same comment as with Fusion - shouldn't actually need to lock for // the duration of volume creation. Should be enough to set a _loading flag, exit the lock, // then re-enter the lock to reset the _loading flag and set any necessary fields. // Locking for the duration means the memory manager could get hung up while trying to unload // a big volume that is in the process of being created. lock (_syncRoot) { if (_volumeReference != null) { return(_volumeReference.Volume); } Progress = 0; using (var volume = Volume.Create(_frames, (n, total) => { Progress = Math.Min(100f, 100f * n / total); if (callback != null) { callback.Invoke(this, n, total); } _largeObjectContainerData.UpdateLastAccessTime(); #if UNIT_TESTS if (ThrowAsyncVolumeLoadException) { ThrowAsyncVolumeLoadException = false; throw new CreateVolumeException("User manually triggered exception"); } #endif })) { _volumeReference = volume.CreateReference(); _largeObjectContainerData.LargeObjectCount = 1; _largeObjectContainerData.BytesHeldCount = 2 * volume.ArrayLength; _largeObjectContainerData.UpdateLastAccessTime(); MemoryManager.Add(this); } Progress = 100f; return(_volumeReference.Volume); } }
private Volume LoadCore(VolumeLoadProgressCallback callback) { if (_volumeReference != null) { return(_volumeReference.Volume); } lock (_syncRoot) { if (_volumeReference != null) { return(_volumeReference.Volume); } Progress = 0; using (var volume = Volume.Create(_frames, (n, total) => { Progress = Math.Min(100f, 100f * n / total); if (callback != null) { callback.Invoke(this, n, total); } })) { _volumeReference = volume.CreateTransientReference(); _largeObjectContainerData.LargeObjectCount = 1; _largeObjectContainerData.BytesHeldCount = 2 * volume.SizeInVoxels; _largeObjectContainerData.UpdateLastAccessTime(); MemoryManager.Add(this); } Progress = 100f; return(_volumeReference.Volume); } }
public void Load(VolumeLoadProgressCallback callback = null) { _cachedVolume.Load(callback); }
// TODO (CR Apr 2013): API is a bit overloaded; the task provides completion and error info already // so probably all that is needed is the progress callback argument. public Task LoadAsync(VolumeLoadProgressCallback onProgress = null, VolumeLoadCompletionCallback onComplete = null, VolumeLoadErrorCallback onError = null) { return(_cachedVolume.LoadAsync(onProgress, onComplete, onError)); }
// TODO (CR Apr 2013): the reason this is overloaded is because there's not always a task to return. Would be better // to return some other object, possibly with the task as a property, but also with the volume itself, if it's available. private Task LoadAsync(VolumeLoadProgressCallback onProgress = null, VolumeLoadCompletionCallback onComplete = null, VolumeLoadErrorCallback onError = null) { AssertNotDisposed(); // TODO (CR Apr 2013): Not a good idea to return nothing; why not return a struct with the volume in it? if (_volumeReference != null) { return(null); } if (_backgroundLoadTask != null) { return(_backgroundLoadTask); } lock (_backgroundLoadSyncRoot) { if (_volumeReference != null) { return(null); } if (_backgroundLoadTask != null) { return(_backgroundLoadTask); } _backgroundLoadTask = new Task(() => LoadCore(onProgress)); _backgroundLoadTask.ContinueWith(t => { // TODO (CR Apr 2013): Can probably just lock the part that // changes the _backgroundLoadTask variable. lock (_backgroundLoadSyncRoot) { if (t.IsFaulted && t.Exception != null) { var ex = t.Exception.Flatten().InnerExceptions.FirstOrDefault(); if (onError != null) { onError.Invoke(this, ex); } else { Platform.Log(LogLevel.Warn, ex, "Unhandled exception thrown in background volume loader"); } } else { if (onComplete != null) { onComplete.Invoke(this); } } if (ReferenceEquals(t, _backgroundLoadTask)) { _backgroundLoadTask.Dispose(); _backgroundLoadTask = null; } } }); _backgroundLoadTask.Start(); return(_backgroundLoadTask); } }
private void Load(VolumeLoadProgressCallback callback = null) { AssertNotDisposed(); LoadCore(callback); }