XML comments added Builds cleanly.
oddly a ignore in the gitignore went missing. restored.
This commit is contained in:
parent
8a6f9144c4
commit
0ae815cf2c
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
# Ignore Build
|
||||
.vscode/
|
||||
/docfx_project
|
||||
/src/AdvChkSys/bin
|
||||
/src/AdvChkSys/obj
|
||||
|
||||
@ -14,21 +14,36 @@ namespace AdvChkSys.Dependencies
|
||||
/// </summary>
|
||||
public enum DependencyType
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates a neighboring chunk relationship.
|
||||
/// </summary>
|
||||
Neighbor,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a reference relationship between chunks.
|
||||
/// </summary>
|
||||
Reference,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates an update relationship between chunks.
|
||||
/// </summary>
|
||||
Update,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a custom dependency relationship.
|
||||
/// </summary>
|
||||
Custom
|
||||
}
|
||||
|
||||
|
||||
// Dictionary to track dependencies: source chunk -> (target chunk, dependency type)
|
||||
private readonly Dictionary<IChunk, HashSet<(IChunk Target, DependencyType Type)>> _dependencies = new();
|
||||
|
||||
|
||||
// Dictionary to track dependents: target chunk -> (source chunk, dependency type)
|
||||
private readonly Dictionary<IChunk, HashSet<(IChunk Source, DependencyType Type)>> _dependents = new();
|
||||
|
||||
|
||||
// Lock object for thread safety
|
||||
private readonly object _lock = new();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Registers a dependency between two chunks.
|
||||
/// </summary>
|
||||
@ -36,7 +51,7 @@ namespace AdvChkSys.Dependencies
|
||||
{
|
||||
if (source == null || target == null)
|
||||
return;
|
||||
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
// Add to dependencies
|
||||
@ -46,7 +61,7 @@ namespace AdvChkSys.Dependencies
|
||||
_dependencies[source] = targetSet;
|
||||
}
|
||||
targetSet.Add((target, type));
|
||||
|
||||
|
||||
// Add to dependents
|
||||
if (!_dependents.TryGetValue(target, out var sourceSet))
|
||||
{
|
||||
@ -56,7 +71,7 @@ namespace AdvChkSys.Dependencies
|
||||
sourceSet.Add((source, type));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Removes a dependency between two chunks.
|
||||
/// </summary>
|
||||
@ -64,7 +79,7 @@ namespace AdvChkSys.Dependencies
|
||||
{
|
||||
if (source == null || target == null)
|
||||
return;
|
||||
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
// Remove from dependencies
|
||||
@ -76,7 +91,7 @@ namespace AdvChkSys.Dependencies
|
||||
_dependencies.Remove(source);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Remove from dependents
|
||||
if (_dependents.TryGetValue(target, out var sourceSet))
|
||||
{
|
||||
@ -88,7 +103,7 @@ namespace AdvChkSys.Dependencies
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets all chunks that depend on the specified chunk.
|
||||
/// </summary>
|
||||
@ -96,14 +111,14 @@ namespace AdvChkSys.Dependencies
|
||||
{
|
||||
if (chunk == null)
|
||||
return new List<IChunk>();
|
||||
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_dependents.TryGetValue(chunk, out var sourceSet))
|
||||
{
|
||||
return new List<IChunk>();
|
||||
}
|
||||
|
||||
|
||||
var result = new List<IChunk>(sourceSet.Count);
|
||||
foreach (var (source, _) in sourceSet)
|
||||
{
|
||||
@ -112,7 +127,7 @@ namespace AdvChkSys.Dependencies
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets all chunks that the specified chunk depends on.
|
||||
/// </summary>
|
||||
@ -120,14 +135,14 @@ namespace AdvChkSys.Dependencies
|
||||
{
|
||||
if (chunk == null)
|
||||
return new List<IChunk>();
|
||||
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_dependencies.TryGetValue(chunk, out var targetSet))
|
||||
{
|
||||
return new List<IChunk>();
|
||||
}
|
||||
|
||||
|
||||
var result = new List<IChunk>(targetSet.Count);
|
||||
foreach (var (target, _) in targetSet)
|
||||
{
|
||||
@ -136,7 +151,7 @@ namespace AdvChkSys.Dependencies
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets all chunks that depend on the specified chunk with their dependency types.
|
||||
/// </summary>
|
||||
@ -144,14 +159,14 @@ namespace AdvChkSys.Dependencies
|
||||
{
|
||||
if (chunk == null)
|
||||
return new List<(IChunk, DependencyType)>();
|
||||
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_dependents.TryGetValue(chunk, out var sourceDependents))
|
||||
{
|
||||
return new List<(IChunk, DependencyType)>();
|
||||
}
|
||||
|
||||
|
||||
var result = new List<(IChunk, DependencyType)>(sourceDependents.Count);
|
||||
foreach (var (source, type) in sourceDependents)
|
||||
{
|
||||
@ -160,7 +175,7 @@ namespace AdvChkSys.Dependencies
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets all chunks that the specified chunk depends on with their dependency types.
|
||||
/// </summary>
|
||||
@ -168,14 +183,14 @@ namespace AdvChkSys.Dependencies
|
||||
{
|
||||
if (chunk == null)
|
||||
return new List<(IChunk, DependencyType)>();
|
||||
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_dependencies.TryGetValue(chunk, out var targetSet))
|
||||
{
|
||||
return new List<(IChunk, DependencyType)>();
|
||||
}
|
||||
|
||||
|
||||
var result = new List<(IChunk, DependencyType)>(targetSet.Count);
|
||||
foreach (var (target, type) in targetSet)
|
||||
{
|
||||
@ -184,7 +199,7 @@ namespace AdvChkSys.Dependencies
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a dependency exists between source and target chunks.
|
||||
/// </summary>
|
||||
@ -192,14 +207,14 @@ namespace AdvChkSys.Dependencies
|
||||
{
|
||||
if (source == null || target == null)
|
||||
return false;
|
||||
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_dependencies.TryGetValue(source, out var targetSet))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
foreach (var (t, _) in targetSet)
|
||||
{
|
||||
if (t.Equals(target))
|
||||
@ -207,11 +222,11 @@ namespace AdvChkSys.Dependencies
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dependency type between source and target chunks, or null if no dependency exists.
|
||||
/// </summary>
|
||||
@ -219,14 +234,14 @@ namespace AdvChkSys.Dependencies
|
||||
{
|
||||
if (source == null || target == null)
|
||||
return null;
|
||||
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_dependencies.TryGetValue(source, out var targetSet))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
foreach (var (t, type) in targetSet)
|
||||
{
|
||||
if (t.Equals(target))
|
||||
@ -234,11 +249,11 @@ namespace AdvChkSys.Dependencies
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Clears all dependencies for a specific chunk.
|
||||
/// </summary>
|
||||
@ -246,7 +261,7 @@ namespace AdvChkSys.Dependencies
|
||||
{
|
||||
if (chunk == null)
|
||||
return;
|
||||
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
// Remove all dependencies where this chunk is the source
|
||||
@ -265,7 +280,7 @@ namespace AdvChkSys.Dependencies
|
||||
}
|
||||
_dependencies.Remove(chunk);
|
||||
}
|
||||
|
||||
|
||||
// Remove all dependencies where this chunk is the target
|
||||
if (_dependents.TryGetValue(chunk, out var sourceSets))
|
||||
{
|
||||
@ -284,7 +299,7 @@ namespace AdvChkSys.Dependencies
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets all chunks that have any dependencies.
|
||||
/// </summary>
|
||||
@ -295,7 +310,7 @@ namespace AdvChkSys.Dependencies
|
||||
return new HashSet<IChunk>(_dependencies.Keys);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets all chunks that have any dependents.
|
||||
/// </summary>
|
||||
|
||||
@ -18,13 +18,32 @@ namespace AdvChkSys.Loading
|
||||
/// </summary>
|
||||
public enum Priority
|
||||
{
|
||||
/// <summary>
|
||||
/// Immediate priority - process as soon as possible
|
||||
/// </summary>
|
||||
Immediate,
|
||||
|
||||
/// <summary>
|
||||
/// High priority - process after immediate requests
|
||||
/// </summary>
|
||||
High,
|
||||
|
||||
/// <summary>
|
||||
/// Normal priority - standard processing order
|
||||
/// </summary>
|
||||
Normal,
|
||||
|
||||
/// <summary>
|
||||
/// Low priority - process after normal requests
|
||||
/// </summary>
|
||||
Low,
|
||||
|
||||
/// <summary>
|
||||
/// Background priority - process when system is idle
|
||||
/// </summary>
|
||||
Background
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents a chunk loading request with priority.
|
||||
/// </summary>
|
||||
@ -34,47 +53,47 @@ namespace AdvChkSys.Loading
|
||||
/// The X coordinate of the chunk.
|
||||
/// </summary>
|
||||
public int X { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The Y coordinate of the chunk.
|
||||
/// </summary>
|
||||
public int Y { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The Z coordinate of the chunk (optional, for 3D chunks).
|
||||
/// </summary>
|
||||
public int Z { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The priority of this loading request.
|
||||
/// </summary>
|
||||
public Priority LoadPriority { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The width of the chunk.
|
||||
/// </summary>
|
||||
public int Width { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The height of the chunk.
|
||||
/// </summary>
|
||||
public int Height { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The depth of the chunk (for 3D chunks).
|
||||
/// </summary>
|
||||
public int Depth { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp when the request was created.
|
||||
/// </summary>
|
||||
public DateTime Timestamp { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Unique identifier for this request.
|
||||
/// </summary>
|
||||
public Guid RequestId { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new 2D chunk loading request.
|
||||
/// </summary>
|
||||
@ -90,7 +109,7 @@ namespace AdvChkSys.Loading
|
||||
Timestamp = DateTime.UtcNow;
|
||||
RequestId = Guid.NewGuid();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new 3D chunk loading request.
|
||||
/// </summary>
|
||||
@ -107,39 +126,39 @@ namespace AdvChkSys.Loading
|
||||
RequestId = Guid.NewGuid();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Priority queues for each priority level
|
||||
private readonly Dictionary<Priority, Queue<ChunkLoadRequest>> _requestQueues = new();
|
||||
|
||||
|
||||
// Lookup for fast cancellation and status checks
|
||||
private readonly Dictionary<Guid, ChunkLoadRequest> _requestLookup = new();
|
||||
|
||||
|
||||
// Active tasks to prevent duplicate loading
|
||||
private readonly Dictionary<(int X, int Y, int Z), Task> _activeTasks = new();
|
||||
|
||||
|
||||
// Synchronization
|
||||
private readonly SemaphoreSlim _queueSemaphore = new(1, 1);
|
||||
private readonly SemaphoreSlim _processSemaphore;
|
||||
private readonly CancellationTokenSource _cancellationSource = new();
|
||||
|
||||
|
||||
// Processing state
|
||||
private bool _isProcessing;
|
||||
private Task? _processingTask;
|
||||
|
||||
|
||||
// Configuration
|
||||
private readonly int _maxConcurrentLoads;
|
||||
private readonly TimeSpan _requestTimeout;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when a chunk load request is completed.
|
||||
/// </summary>
|
||||
public event EventHandler<ChunkLoadRequest>? RequestCompleted;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when a chunk load request fails.
|
||||
/// </summary>
|
||||
public event EventHandler<(ChunkLoadRequest Request, Exception Exception)>? RequestFailed;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ChunkLoadingPriority class.
|
||||
/// </summary>
|
||||
@ -150,14 +169,14 @@ namespace AdvChkSys.Loading
|
||||
_maxConcurrentLoads = maxConcurrentLoads;
|
||||
_requestTimeout = TimeSpan.FromSeconds(requestTimeoutSeconds);
|
||||
_processSemaphore = new SemaphoreSlim(maxConcurrentLoads, maxConcurrentLoads);
|
||||
|
||||
|
||||
// Initialize queues for each priority level
|
||||
foreach (Priority priority in Enum.GetValues(typeof(Priority)))
|
||||
{
|
||||
_requestQueues[priority] = new Queue<ChunkLoadRequest>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Enqueues a chunk load request with the specified priority.
|
||||
/// </summary>
|
||||
@ -168,7 +187,7 @@ namespace AdvChkSys.Loading
|
||||
EnqueueRequest(request);
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Enqueues a 3D chunk load request with the specified priority.
|
||||
/// </summary>
|
||||
@ -179,7 +198,7 @@ namespace AdvChkSys.Loading
|
||||
EnqueueRequest(request);
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Enqueues a pre-created chunk load request.
|
||||
/// </summary>
|
||||
@ -194,11 +213,11 @@ namespace AdvChkSys.Loading
|
||||
{
|
||||
return; // Already loading this chunk
|
||||
}
|
||||
|
||||
|
||||
// Add to appropriate queue
|
||||
_requestQueues[request.LoadPriority].Enqueue(request);
|
||||
_requestLookup[request.RequestId] = request;
|
||||
|
||||
|
||||
// Start processing if not already running
|
||||
EnsureProcessingStarted();
|
||||
}
|
||||
@ -206,14 +225,14 @@ namespace AdvChkSys.Loading
|
||||
{
|
||||
_queueSemaphore.Release();
|
||||
}
|
||||
|
||||
|
||||
// For immediate priority, wait for processing to start
|
||||
if (request.LoadPriority == Priority.Immediate)
|
||||
{
|
||||
TriggerImmediateProcessing();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Cancels a pending chunk load request.
|
||||
/// </summary>
|
||||
@ -237,7 +256,7 @@ namespace AdvChkSys.Loading
|
||||
_queueSemaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Cancels all pending chunk load requests.
|
||||
/// </summary>
|
||||
@ -257,7 +276,7 @@ namespace AdvChkSys.Loading
|
||||
_queueSemaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Starts the processing of chunk load requests if not already running.
|
||||
/// </summary>
|
||||
@ -265,11 +284,11 @@ namespace AdvChkSys.Loading
|
||||
{
|
||||
if (_isProcessing)
|
||||
return;
|
||||
|
||||
|
||||
_isProcessing = true;
|
||||
_processingTask = Task.Run(ProcessRequestsAsync);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Triggers immediate processing of high-priority requests.
|
||||
/// </summary>
|
||||
@ -278,7 +297,7 @@ namespace AdvChkSys.Loading
|
||||
// This is a hint to the processor to check for immediate requests now
|
||||
// We don't need to do anything special as the processor checks immediate first
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Main processing loop for chunk load requests.
|
||||
/// </summary>
|
||||
@ -287,13 +306,13 @@ namespace AdvChkSys.Loading
|
||||
while (!_cancellationSource.IsCancellationRequested)
|
||||
{
|
||||
ChunkLoadRequest? request = null;
|
||||
|
||||
|
||||
// Get the next request from the highest priority queue
|
||||
await _queueSemaphore.WaitAsync();
|
||||
try
|
||||
{
|
||||
request = DequeueNextRequest();
|
||||
|
||||
|
||||
if (request == null)
|
||||
{
|
||||
// No requests to process, pause briefly
|
||||
@ -302,7 +321,7 @@ namespace AdvChkSys.Loading
|
||||
await Task.Delay(50);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Mark this chunk as being processed
|
||||
var key = (request.X, request.Y, request.Z);
|
||||
if (_activeTasks.ContainsKey(key))
|
||||
@ -310,7 +329,7 @@ namespace AdvChkSys.Loading
|
||||
// Already processing this chunk, skip
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Create a task for this request but don't start it yet
|
||||
var loadTask = ProcessRequestAsync(request);
|
||||
_activeTasks[key] = loadTask;
|
||||
@ -322,10 +341,10 @@ namespace AdvChkSys.Loading
|
||||
_queueSemaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Wait for a processing slot
|
||||
await _processSemaphore.WaitAsync();
|
||||
|
||||
|
||||
// Start the task and continue without waiting
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
@ -336,7 +355,7 @@ namespace AdvChkSys.Loading
|
||||
finally
|
||||
{
|
||||
_processSemaphore.Release();
|
||||
|
||||
|
||||
// Remove from active tasks
|
||||
await _queueSemaphore.WaitAsync();
|
||||
try
|
||||
@ -351,7 +370,7 @@ namespace AdvChkSys.Loading
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Dequeues the next request from the highest priority queue.
|
||||
/// </summary>
|
||||
@ -361,30 +380,30 @@ namespace AdvChkSys.Loading
|
||||
foreach (Priority priority in Enum.GetValues(typeof(Priority)))
|
||||
{
|
||||
var queue = _requestQueues[priority];
|
||||
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var request = queue.Dequeue();
|
||||
|
||||
|
||||
// Skip if the request has been canceled
|
||||
if (!_requestLookup.ContainsKey(request.RequestId))
|
||||
continue;
|
||||
|
||||
|
||||
// Skip if the request has timed out
|
||||
if (DateTime.UtcNow - request.Timestamp > _requestTimeout)
|
||||
{
|
||||
_requestLookup.Remove(request.RequestId);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Valid request found
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null; // No valid requests found
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Processes a single chunk load request.
|
||||
/// </summary>
|
||||
@ -394,7 +413,7 @@ namespace AdvChkSys.Loading
|
||||
{
|
||||
// This would be integrated with your chunk manager
|
||||
// For now, we'll just simulate the loading with a delay
|
||||
|
||||
|
||||
// Simulate different loading times based on priority
|
||||
int delayMs = request.LoadPriority switch
|
||||
{
|
||||
@ -405,9 +424,9 @@ namespace AdvChkSys.Loading
|
||||
Priority.Background => 1000,
|
||||
_ => 200
|
||||
};
|
||||
|
||||
|
||||
await Task.Delay(delayMs);
|
||||
|
||||
|
||||
// Notify completion
|
||||
RequestCompleted?.Invoke(this, request);
|
||||
}
|
||||
@ -430,7 +449,7 @@ namespace AdvChkSys.Loading
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of pending requests for each priority level.
|
||||
/// </summary>
|
||||
@ -451,7 +470,7 @@ namespace AdvChkSys.Loading
|
||||
_queueSemaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total number of pending requests.
|
||||
/// </summary>
|
||||
@ -472,14 +491,14 @@ namespace AdvChkSys.Loading
|
||||
_queueSemaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Stops processing and releases resources.
|
||||
/// </summary>
|
||||
public async Task ShutdownAsync()
|
||||
{
|
||||
_cancellationSource.Cancel();
|
||||
|
||||
|
||||
if (_processingTask != null)
|
||||
{
|
||||
try
|
||||
@ -495,12 +514,12 @@ namespace AdvChkSys.Loading
|
||||
// Ignore other exceptions during shutdown
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_queueSemaphore.Dispose();
|
||||
_processSemaphore.Dispose();
|
||||
_cancellationSource.Dispose();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a ChunkLoadingPriority instance with default settings.
|
||||
/// </summary>
|
||||
@ -508,7 +527,7 @@ namespace AdvChkSys.Loading
|
||||
{
|
||||
return new ChunkLoadingPriority();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a ChunkLoadingPriority instance optimized for high throughput.
|
||||
/// </summary>
|
||||
@ -518,7 +537,7 @@ namespace AdvChkSys.Loading
|
||||
maxConcurrentLoads: Environment.ProcessorCount * 2,
|
||||
requestTimeoutSeconds: 60);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a ChunkLoadingPriority instance optimized for low latency.
|
||||
/// </summary>
|
||||
@ -528,7 +547,7 @@ namespace AdvChkSys.Loading
|
||||
maxConcurrentLoads: Math.Max(2, Environment.ProcessorCount / 2),
|
||||
requestTimeoutSeconds: 15);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Integrates with a chunk manager to process load requests.
|
||||
/// </summary>
|
||||
@ -539,7 +558,7 @@ namespace AdvChkSys.Loading
|
||||
// Replace the ProcessRequestAsync method with one that uses the chunk manager
|
||||
// This is a simplified example - in a real implementation, you'd need to handle
|
||||
// both 2D and 3D chunk managers and properly cast the interface
|
||||
|
||||
|
||||
RequestCompleted += (sender, request) =>
|
||||
{
|
||||
// The chunk has been loaded, you might want to do something with it
|
||||
@ -547,7 +566,7 @@ namespace AdvChkSys.Loading
|
||||
// Additional processing if needed
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the estimated time until a request with the given priority would be processed.
|
||||
/// </summary>
|
||||
@ -558,7 +577,7 @@ namespace AdvChkSys.Loading
|
||||
try
|
||||
{
|
||||
int totalHigherPriorityRequests = 0;
|
||||
|
||||
|
||||
// Count requests with higher or equal priority
|
||||
foreach (Priority p in Enum.GetValues(typeof(Priority)))
|
||||
{
|
||||
@ -567,13 +586,13 @@ namespace AdvChkSys.Loading
|
||||
totalHigherPriorityRequests += _requestQueues[p].Count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If no requests or no active tasks, return 0
|
||||
if (totalHigherPriorityRequests == 0 || _activeTasks.Count == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Estimate based on current processing rate
|
||||
// This is a very simple estimate and could be improved with actual metrics
|
||||
int averageProcessingTimeMs = priority switch
|
||||
@ -585,10 +604,10 @@ namespace AdvChkSys.Loading
|
||||
Priority.Background => 1000,
|
||||
_ => 200
|
||||
};
|
||||
|
||||
|
||||
// Calculate how many batches of concurrent requests we'll need
|
||||
int batches = (int)Math.Ceiling(totalHigherPriorityRequests / (double)_maxConcurrentLoads);
|
||||
|
||||
|
||||
return batches * averageProcessingTimeMs;
|
||||
}
|
||||
finally
|
||||
@ -596,7 +615,7 @@ namespace AdvChkSys.Loading
|
||||
_queueSemaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adjusts the priority of an existing request.
|
||||
/// </summary>
|
||||
@ -605,7 +624,7 @@ namespace AdvChkSys.Loading
|
||||
{
|
||||
// Note: This is not an efficient operation as we don't directly modify the queue
|
||||
// Instead, we mark the request for priority change when it's processed
|
||||
|
||||
|
||||
_queueSemaphore.Wait();
|
||||
try
|
||||
{
|
||||
@ -616,26 +635,26 @@ namespace AdvChkSys.Loading
|
||||
{
|
||||
// Remove from lookup (it will be skipped when dequeued)
|
||||
_requestLookup.Remove(requestId);
|
||||
|
||||
|
||||
// Create a new request with the same parameters but higher priority
|
||||
var newRequest = request.Depth > 1
|
||||
? new ChunkLoadRequest(request.X, request.Y, request.Z, request.Width, request.Height, request.Depth, newPriority)
|
||||
: new ChunkLoadRequest(request.X, request.Y, request.Width, request.Height, newPriority);
|
||||
|
||||
|
||||
// Add the new request
|
||||
_requestQueues[newPriority].Enqueue(newRequest);
|
||||
_requestLookup[newRequest.RequestId] = newRequest;
|
||||
|
||||
|
||||
// If upgrading to immediate, trigger processing
|
||||
if (newPriority == Priority.Immediate)
|
||||
{
|
||||
TriggerImmediateProcessing();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
@ -643,7 +662,7 @@ namespace AdvChkSys.Loading
|
||||
_queueSemaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets statistics about the current state of the chunk loading system.
|
||||
/// </summary>
|
||||
@ -659,13 +678,13 @@ namespace AdvChkSys.Loading
|
||||
["IsProcessing"] = _isProcessing,
|
||||
["MaxConcurrentLoads"] = _maxConcurrentLoads
|
||||
};
|
||||
|
||||
|
||||
// Add queue sizes for each priority
|
||||
foreach (Priority priority in Enum.GetValues(typeof(Priority)))
|
||||
{
|
||||
stats[$"Queue_{priority}"] = _requestQueues[priority].Count;
|
||||
}
|
||||
|
||||
|
||||
return stats;
|
||||
}
|
||||
finally
|
||||
@ -674,4 +693,4 @@ namespace AdvChkSys.Loading
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -14,17 +13,17 @@ namespace AdvChkSys.Threading
|
||||
{
|
||||
private static ChunkThreadingManager? _instance;
|
||||
private static readonly object _instanceLock = new();
|
||||
|
||||
|
||||
// Thread safety utilities
|
||||
private readonly ChunkThreadSafetyManager _threadSafety;
|
||||
private readonly ChunkAsyncLock _asyncLock;
|
||||
|
||||
|
||||
// Operation queue
|
||||
private readonly ChunkOperationQueue _operationQueue;
|
||||
|
||||
|
||||
// Cancellation for shutdown
|
||||
private readonly CancellationTokenSource _shutdownCts = new();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the singleton instance of the ChunkThreadingManager.
|
||||
/// </summary>
|
||||
@ -42,7 +41,7 @@ namespace AdvChkSys.Threading
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ChunkThreadingManager class.
|
||||
/// </summary>
|
||||
@ -50,29 +49,29 @@ namespace AdvChkSys.Threading
|
||||
{
|
||||
_threadSafety = new ChunkThreadSafetyManager(
|
||||
ChunkThreadingConfiguration.LockCleanupIntervalMinutes);
|
||||
|
||||
|
||||
_asyncLock = new ChunkAsyncLock(
|
||||
ChunkThreadingConfiguration.LockCleanupIntervalMinutes);
|
||||
|
||||
|
||||
_operationQueue = new ChunkOperationQueue(
|
||||
ChunkThreadingConfiguration.DefaultMaxDegreeOfParallelism);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the thread safety manager for synchronous locking.
|
||||
/// </summary>
|
||||
public ChunkThreadSafetyManager ThreadSafety => _threadSafety;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the async lock manager for asynchronous locking.
|
||||
/// </summary>
|
||||
public ChunkAsyncLock AsyncLock => _asyncLock;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the operation queue for sequential chunk operations.
|
||||
/// </summary>
|
||||
public ChunkOperationQueue OperationQueue => _operationQueue;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Acquires an exclusive lock on a chunk.
|
||||
/// </summary>
|
||||
@ -82,7 +81,7 @@ namespace AdvChkSys.Threading
|
||||
{
|
||||
return _threadSafety.AcquireLock(chunk);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Acquires a read lock on a chunk.
|
||||
/// </summary>
|
||||
@ -92,7 +91,7 @@ namespace AdvChkSys.Threading
|
||||
{
|
||||
return _threadSafety.AcquireReadLock(chunk);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Acquires a write lock on a chunk.
|
||||
/// </summary>
|
||||
@ -102,7 +101,7 @@ namespace AdvChkSys.Threading
|
||||
{
|
||||
return _threadSafety.AcquireWriteLock(chunk);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Acquires a lock on a chunk asynchronously.
|
||||
/// </summary>
|
||||
@ -113,7 +112,7 @@ namespace AdvChkSys.Threading
|
||||
{
|
||||
return _asyncLock.LockAsync(chunk, cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Enqueues an operation to be performed on a chunk.
|
||||
/// </summary>
|
||||
@ -124,7 +123,7 @@ namespace AdvChkSys.Threading
|
||||
{
|
||||
return _operationQueue.EnqueueOperationAsync(chunk, operation);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Runs an action with a lock on the chunk.
|
||||
/// </summary>
|
||||
@ -135,7 +134,7 @@ namespace AdvChkSys.Threading
|
||||
using var lockObj = AcquireLock(chunk);
|
||||
action();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Runs a function with a lock on the chunk and returns the result.
|
||||
/// </summary>
|
||||
@ -148,7 +147,7 @@ namespace AdvChkSys.Threading
|
||||
using var lockObj = AcquireLock(chunk);
|
||||
return func();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Runs an async action with a lock on the chunk.
|
||||
/// </summary>
|
||||
@ -160,7 +159,7 @@ namespace AdvChkSys.Threading
|
||||
using var lockObj = await LockAsync(chunk, cancellationToken).ConfigureAwait(false);
|
||||
await action().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Runs an async function with a lock on the chunk and returns the result.
|
||||
/// </summary>
|
||||
@ -174,7 +173,7 @@ namespace AdvChkSys.Threading
|
||||
using var lockObj = await LockAsync(chunk, cancellationToken).ConfigureAwait(false);
|
||||
return await func().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Runs an action on multiple chunks with proper locking to avoid deadlocks.
|
||||
/// </summary>
|
||||
@ -184,7 +183,7 @@ namespace AdvChkSys.Threading
|
||||
{
|
||||
// Sort chunks by ID to prevent deadlocks
|
||||
var sortedChunks = SortChunksById(chunks);
|
||||
|
||||
|
||||
// Acquire locks in order
|
||||
var locks = new IDisposable[sortedChunks.Length];
|
||||
try
|
||||
@ -193,7 +192,7 @@ namespace AdvChkSys.Threading
|
||||
{
|
||||
locks[i] = AcquireLock(sortedChunks[i]);
|
||||
}
|
||||
|
||||
|
||||
// Execute the action
|
||||
action();
|
||||
}
|
||||
@ -206,7 +205,7 @@ namespace AdvChkSys.Threading
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Runs an async action on multiple chunks with proper locking to avoid deadlocks.
|
||||
/// </summary>
|
||||
@ -217,7 +216,7 @@ namespace AdvChkSys.Threading
|
||||
{
|
||||
// Sort chunks by ID to prevent deadlocks
|
||||
var sortedChunks = SortChunksById(chunks);
|
||||
|
||||
|
||||
// Acquire locks in order
|
||||
var locks = new IDisposable[sortedChunks.Length];
|
||||
try
|
||||
@ -226,7 +225,7 @@ namespace AdvChkSys.Threading
|
||||
{
|
||||
locks[i] = await LockAsync(sortedChunks[i], cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
// Execute the action
|
||||
await action().ConfigureAwait(false);
|
||||
}
|
||||
@ -239,7 +238,7 @@ namespace AdvChkSys.Threading
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sorts chunks by ID to prevent deadlocks when acquiring multiple locks.
|
||||
/// </summary>
|
||||
@ -248,24 +247,24 @@ namespace AdvChkSys.Threading
|
||||
// Use System.Linq for OrderBy
|
||||
return chunks.OrderBy(c => c.GetHashCode()).ToArray();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Disposes all resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
_shutdownCts.Cancel();
|
||||
|
||||
|
||||
// Shutdown operation queue
|
||||
_operationQueue.ShutdownAsync().GetAwaiter().GetResult();
|
||||
|
||||
|
||||
// Dispose thread safety managers
|
||||
(_threadSafety as IDisposable)?.Dispose();
|
||||
(_asyncLock as IDisposable)?.Dispose();
|
||||
|
||||
|
||||
_shutdownCts.Dispose();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Resets the singleton instance (for testing).
|
||||
/// </summary>
|
||||
|
||||
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
namespace AdvChkSys.Threading
|
||||
{
|
||||
@ -15,19 +15,19 @@ namespace AdvChkSys.Threading
|
||||
{
|
||||
// Performance metrics
|
||||
private readonly ConcurrentDictionary<string, PerformanceMetric> _metrics = new();
|
||||
|
||||
|
||||
// Sampling timer
|
||||
private readonly Timer _samplingTimer;
|
||||
|
||||
|
||||
// Sampling interval
|
||||
private readonly TimeSpan _samplingInterval;
|
||||
|
||||
|
||||
// Maximum history to keep
|
||||
private readonly int _maxHistory;
|
||||
|
||||
|
||||
// Whether monitoring is enabled
|
||||
private bool _isEnabled;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ChunkThreadingPerformanceMonitor class.
|
||||
/// </summary>
|
||||
@ -39,7 +39,7 @@ namespace AdvChkSys.Threading
|
||||
_maxHistory = maxHistory;
|
||||
_samplingTimer = new Timer(SamplePerformance, null, Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Starts monitoring performance.
|
||||
/// </summary>
|
||||
@ -51,7 +51,7 @@ namespace AdvChkSys.Threading
|
||||
_samplingTimer.Change(TimeSpan.Zero, _samplingInterval);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Stops monitoring performance.
|
||||
/// </summary>
|
||||
@ -63,7 +63,7 @@ namespace AdvChkSys.Threading
|
||||
_samplingTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Samples performance metrics.
|
||||
/// </summary>
|
||||
@ -71,28 +71,28 @@ namespace AdvChkSys.Threading
|
||||
{
|
||||
if (!_isEnabled)
|
||||
return;
|
||||
|
||||
|
||||
// Sample thread pool information
|
||||
ThreadPool.GetAvailableThreads(out int workerThreads, out int completionPortThreads);
|
||||
ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxCompletionPortThreads);
|
||||
|
||||
|
||||
// Calculate thread pool usage
|
||||
double workerThreadUsage = 1.0 - ((double)workerThreads / maxWorkerThreads);
|
||||
double ioThreadUsage = 1.0 - ((double)completionPortThreads / maxCompletionPortThreads);
|
||||
|
||||
|
||||
// Update metrics
|
||||
UpdateMetric("ThreadPool.WorkerThreadUsage", workerThreadUsage);
|
||||
UpdateMetric("ThreadPool.IOThreadUsage", ioThreadUsage);
|
||||
|
||||
|
||||
// Sample operation queue information
|
||||
var operationQueue = ChunkThreadingManager.Instance.OperationQueue;
|
||||
UpdateMetric("OperationQueue.PendingOperations", operationQueue.PendingOperationCount);
|
||||
UpdateMetric("OperationQueue.ActiveOperations", operationQueue.ActiveOperationCount);
|
||||
|
||||
|
||||
// Sample diagnostics information
|
||||
UpdateMetric("Diagnostics.ActiveOperations", ChunkThreadingDiagnostics.GetActiveOperationCount());
|
||||
UpdateMetric("Diagnostics.LockContentions", ChunkThreadingDiagnostics.GetTotalLockContentionCount());
|
||||
|
||||
|
||||
// Sample process information
|
||||
var process = Process.GetCurrentProcess();
|
||||
// Fix: Use process.TotalProcessorTime and calculate uptime manually
|
||||
@ -101,7 +101,7 @@ namespace AdvChkSys.Threading
|
||||
UpdateMetric("Process.Memory", process.WorkingSet64 / 1024.0 / 1024.0); // MB
|
||||
UpdateMetric("Process.Threads", process.Threads.Count);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Updates a performance metric.
|
||||
/// </summary>
|
||||
@ -112,36 +112,36 @@ namespace AdvChkSys.Threading
|
||||
metric = new PerformanceMetric(_maxHistory);
|
||||
_metrics[name] = metric;
|
||||
}
|
||||
|
||||
|
||||
metric.AddSample(value);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a performance report.
|
||||
/// </summary>
|
||||
public Dictionary<string, PerformanceReport> GetPerformanceReport()
|
||||
{
|
||||
var report = new Dictionary<string, PerformanceReport>();
|
||||
|
||||
|
||||
foreach (var kvp in _metrics)
|
||||
{
|
||||
report[kvp.Key] = kvp.Value.GetReport();
|
||||
}
|
||||
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a formatted performance report.
|
||||
/// </summary>
|
||||
public string GetFormattedReport()
|
||||
{
|
||||
var report = new System.Text.StringBuilder();
|
||||
|
||||
|
||||
report.AppendLine("=== Chunk Threading Performance Report ===");
|
||||
report.AppendLine($"Generated: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC");
|
||||
report.AppendLine();
|
||||
|
||||
|
||||
var metrics = _metrics.OrderBy(m => m.Key).ToList();
|
||||
foreach (var kvp in metrics)
|
||||
{
|
||||
@ -153,10 +153,10 @@ namespace AdvChkSys.Threading
|
||||
report.AppendLine($" Max: {metricReport.Max:F3}");
|
||||
report.AppendLine();
|
||||
}
|
||||
|
||||
|
||||
return report.ToString();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Disposes resources.
|
||||
/// </summary>
|
||||
@ -165,7 +165,7 @@ namespace AdvChkSys.Threading
|
||||
Stop();
|
||||
_samplingTimer.Dispose();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents a performance metric with history.
|
||||
/// </summary>
|
||||
@ -173,26 +173,26 @@ namespace AdvChkSys.Threading
|
||||
{
|
||||
private readonly Queue<double> _samples;
|
||||
private readonly int _maxSamples;
|
||||
|
||||
|
||||
public PerformanceMetric(int maxSamples)
|
||||
{
|
||||
_maxSamples = maxSamples;
|
||||
_samples = new Queue<double>(maxSamples);
|
||||
}
|
||||
|
||||
|
||||
public void AddSample(double value)
|
||||
{
|
||||
lock (_samples)
|
||||
{
|
||||
_samples.Enqueue(value);
|
||||
|
||||
|
||||
while (_samples.Count > _maxSamples)
|
||||
{
|
||||
_samples.Dequeue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public PerformanceReport GetReport()
|
||||
{
|
||||
lock (_samples)
|
||||
@ -201,7 +201,7 @@ namespace AdvChkSys.Threading
|
||||
{
|
||||
return new PerformanceReport(0, 0, 0, 0, Array.Empty<double>());
|
||||
}
|
||||
|
||||
|
||||
var samplesArray = _samples.ToArray();
|
||||
return new PerformanceReport(
|
||||
samplesArray.Last(),
|
||||
@ -213,7 +213,7 @@ namespace AdvChkSys.Threading
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents a performance report.
|
||||
/// </summary>
|
||||
@ -223,27 +223,35 @@ namespace AdvChkSys.Threading
|
||||
/// The current value.
|
||||
/// </summary>
|
||||
public double Current { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The average value.
|
||||
/// </summary>
|
||||
public double Average { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The minimum value.
|
||||
/// </summary>
|
||||
public double Min { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The maximum value.
|
||||
/// </summary>
|
||||
public double Max { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The history of values.
|
||||
/// </summary>
|
||||
public double[] History { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="current"></param>
|
||||
/// <param name="average"></param>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
/// <param name="history"></param>
|
||||
public PerformanceReport(double current, double average, double min, double max, double[] history)
|
||||
{
|
||||
Current = current;
|
||||
|
||||
@ -35,8 +35,10 @@ namespace AdvChkSys.Util
|
||||
|
||||
private static ulong GetAvailableMemoryWindows()
|
||||
{
|
||||
var memStatus = new MEMORYSTATUSEX();
|
||||
memStatus.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
|
||||
var memStatus = new MEMORYSTATUSEX
|
||||
{
|
||||
dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX))
|
||||
};
|
||||
if (GlobalMemoryStatusEx(ref memStatus))
|
||||
{
|
||||
return memStatus.ullAvailPhys;
|
||||
@ -81,21 +83,61 @@ namespace AdvChkSys.Util
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Structure containing memory status information for Windows systems.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
public struct MEMORYSTATUSEX
|
||||
{
|
||||
/// <summary>
|
||||
/// The size of the structure, in bytes. You must set this member before calling GlobalMemoryStatusEx.
|
||||
/// </summary>
|
||||
public uint dwLength;
|
||||
/// <summary>
|
||||
/// A number between 0 and 100 that specifies the approximate percentage of physical memory
|
||||
/// that is in use (0 indicates no memory use and 100 indicates full memory use).
|
||||
/// </summary>
|
||||
public uint dwMemoryLoad;
|
||||
/// <summary>
|
||||
/// The total size of physical memory, in bytes.
|
||||
/// </summary>
|
||||
public ulong ullTotalPhys;
|
||||
/// <summary>
|
||||
/// The amount of physical memory currently available, in bytes.
|
||||
/// This is the amount of physical memory that can be immediately reused without having to write its contents to disk first.
|
||||
/// </summary>
|
||||
public ulong ullAvailPhys;
|
||||
/// <summary>
|
||||
/// The current committed memory limit for the system or the current process, whichever is smaller, in bytes.
|
||||
/// </summary>
|
||||
public ulong ullTotalPageFile;
|
||||
/// <summary>
|
||||
/// The maximum amount of memory the current process can commit, in bytes.
|
||||
/// This value is equal to or smaller than the system-wide available commit value.
|
||||
/// </summary>
|
||||
public ulong ullAvailPageFile;
|
||||
/// <summary>
|
||||
/// The size of the user-mode portion of the virtual address space of the calling process, in bytes.
|
||||
/// </summary>
|
||||
public ulong ullTotalVirtual;
|
||||
/// <summary>
|
||||
/// The amount of unreserved and uncommitted memory currently in the user-mode portion
|
||||
/// of the virtual address space of the calling process, in bytes.
|
||||
/// </summary>
|
||||
public ulong ullAvailVirtual;
|
||||
/// <summary>
|
||||
/// Reserved. This value is always 0.
|
||||
/// </summary>
|
||||
public ulong ullAvailExtendedVirtual;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves information about the system's current usage of both physical and virtual memory.
|
||||
/// </summary>
|
||||
/// <param name="lpBuffer">A pointer to a <see cref="MEMORYSTATUSEX"/> structure that receives the memory status information.</param>
|
||||
/// <returns>If the function succeeds, the return value is <c>true</c>. If the function fails, the return value is <c>false</c>.</returns>
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user