@@ -25,12 +25,19 @@ us = CachePool(Vector{S}, () -> Vector{S}(undef, num_us); thread_safe=false)
25
25
end
26
26
end
27
27
```
28
+
29
+ !!! warning "Escaping values"
30
+ You must not use an acquired value after you have released it;
31
+ the memory may be immediately re-used by some other consumer of
32
+ your cache pool. Do not allow the acquired value to escape
33
+ outside of the `@with_cache` block, or past a `release!()`.
28
34
"""
29
35
mutable struct CachePool{T, THREAD_SAFE}
30
- pool:: Vector{T}
31
- alloc:: Function
36
+ const pool:: Vector{T}
37
+ const alloc:: Function
32
38
lock:: ReentrantLock
33
39
num_alloced:: Int
40
+ num_acquired:: Int
34
41
35
42
function CachePool (T, alloc:: F ; thread_safe:: Bool = true ) where {F}
36
43
return new {T,Val{thread_safe}} (T[], alloc, ReentrantLock (), 0 )
@@ -46,6 +53,7 @@ Returns a cached element of the cache pool, calling `cache.alloc()` if none
46
53
are available.
47
54
"""
48
55
Base. @inline function acquire! (cache:: CachePool{T} , _dummy = nothing ) where {T}
56
+ cache. num_acquired += 1
49
57
if isempty (cache. pool)
50
58
cache. num_alloced += 1
51
59
return cache. alloc ():: T
@@ -60,11 +68,17 @@ Returns the value `val` to the cache pool.
60
68
"""
61
69
Base. @inline function release! (cache:: CachePool , val, _dummy = nothing )
62
70
push! (cache. pool, val)
71
+ cache. num_acquired -= 1
72
+ end
73
+
74
+ function is_fully_released (cache:: CachePool , _dummy = nothing )
75
+ return cache. num_acquired == 0
63
76
end
64
77
65
78
# Thread-safe versions just sub out to the other methods, using `_dummy` to force correct dispatch
66
79
acquire! (cache:: ThreadSafeCachePool ) = @lock cache. lock acquire! (cache, nothing )
67
80
release! (cache:: ThreadSafeCachePool , val) = @lock cache. lock release! (cache, val, nothing )
81
+ is_fully_released (cache:: ThreadSafeCachePool ) = @lock cache. lock is_fully_released (cache, nothing )
68
82
69
83
macro with_cache (cache, name, body)
70
84
return quote
@@ -270,8 +284,8 @@ mutable struct IndependentlyLinearizedSolution{T, S, N}
270
284
time_mask:: BitMatrix
271
285
272
286
# Temporary object used during construction, will be set to `nothing` at the end.
273
- ilsc:: Union{Nothing,IndependentlyLinearizedSolutionChunks{T,S}}
274
- ilsc_cache_pool:: Union{Nothing,ThreadSafeCachePool{IndependentlyLinearizedSolutionChunksCache{T,S}}}
287
+ ilsc:: Union{Nothing,IndependentlyLinearizedSolutionChunks{T,S,N }}
288
+ ilsc_cache_pool:: Union{Nothing,ThreadSafeCachePool{IndependentlyLinearizedSolutionChunksCache{T,S,N }}}
275
289
end
276
290
# Helper function to create an ILS wrapped around an in-progress ILSC
277
291
function IndependentlyLinearizedSolution (ilsc:: IndependentlyLinearizedSolutionChunks{T,S,N} , cache_pool = nothing ) where {T,S,N}
@@ -392,14 +406,17 @@ function finish!(ils::IndependentlyLinearizedSolution{T,S}) where {T,S}
392
406
# Update our struct, release the `ilsc` and its caches
393
407
for t_chunk in ilsc. t_chunks
394
408
release! (ilsc. cache. t_chunks, t_chunk)
409
+ @assert is_fully_released (ilsc. cache. t_chunks)
395
410
end
396
411
for u_idx in 1 : length (ilsc. u_chunks)
397
412
for u_chunk in ilsc. u_chunks[u_idx]
398
413
release! (ilsc. cache. u_chunks, u_chunk)
399
414
end
415
+ @assert is_fully_released (ilsc. cache. u_chunks)
400
416
end
401
417
for time_mask in ilsc. time_masks
402
418
release! (ilsc. cache. time_masks, time_mask)
419
+ @assert is_fully_released (ilsc. cache. time_masks)
403
420
end
404
421
if ils. ilsc_cache_pool != = nothing
405
422
release! (ils. ilsc_cache_pool, ilsc. cache)
0 commit comments