Are Tasks automatically cancelled upon return/completion in Swift? - ios

I am a little uncertain about task cancellation in swift. My question is:
If a task reaches its return line (in this example, Line 4), does this mean it will be automatically canceled? (and thus free up memory + any used thread(s) previously occupied by the Task?)
someBlock {
Task<Bool, Never> {
await doSomeWork()
return true // Line 4
}
}
As a follow-up, what if we then call .task on a SwiftUI View? Does anything change?
SomeView
.task {
await doSomeWork()
}
Thank you for your time!

If a task reaches its return line (in this example, Line 4), does this mean it will be automatically canceled
No. It means it will automatically end in good order. Cancellation of a task is very different and specialized thing. They are both ways of bringing a task to an end, but within that similarity they are effectively opposites of one another.
It does mean that the thread(s) used by the Task are now free for use, but this is not as dramatically important as it might seem, because await also frees the thread(s) used by the Task. That's the whole point of async/await; it is not thread-bound. A Task is not aligned with a single thread, the way a DispatchQueue is; to put it another way, we tend to use queue and thread as loose equivalents of one another, but with a Task, that is not at all the case.
As for what memory is released, it depends on what memory was being retained. The code given is too "pseudo" to draw any conclusions about that. But basically yes, your mental picture of this is right: a Task has a life of its own, and while it lives its code continues to retain whatever it has a strong reference to, and then when it ends (whether through finishing in good order or through cancellation) the Task's life ends (if you have not retained it elsewhere) and therefore so does whatever the Task's code is retaining.
Does anything change
The .task modifier, according to Apple, creates "an asynchronous task with a lifetime that matches that of the ... view". So I would say, yes: the Task no longer just has an independent life of its own, but rather it is being retained behind the scenes (in order that the SwiftUI framework can cancel it if the View goes out of existence), and so whatever its code has strong references to will remain.
On the other hand this might not be terribly important; it depends on whether you're using reference types. References to value types, such as a View, don't have that sort of memory management implications.

Related

Does the POSIX Thread API offer a way to test if the calling thread alreeady holds a lock?

Short question: Does the POSIX thread API offer me a way to determine if the calling thread already holds a particular lock?
Long question:
Suppose I want to protect a data structure with a lock. Acquiring and releasing the lock need to happen in different functions. Calls between the functions involved are rather complex (I am adding multithreading to a 16-year-old code base). For example:
do_dangerous_stuff() does things for which the current thread needs to hold the write lock. Therefore, I acquire the lock at the beginning of the function and release it at the end, as the caller does not necessarily hold the lock.
Another function, do_extra_dangerous_stuff(), calls do_dangerous_stuff(). However, before the call it already does things which also require a write lock, and the data is not consistent until the call to do_dangerous_stuff() returns (so releasing and immediately re-acquiring the lock might break things).
In reality it is more complicated than that. There may be a bunch of functions calling do_dangerous_stuff(), and requiring each of them to obtain the lock before calling do_dangerous_stuff() may be impractical. Sometimes the lock is acquired in one function and released in another.
With a read lock, I could just acquire it multiple times from the same thread, as long as I make sure I release the same number of lock instances that I have acquired. For a write lock, this is not an option (attempting to do so will result in a deadlock). An easy solution would be: test if the current thread already holds the lock and acquire it if not, and conversely, test if the current thread still holds the lock and release it if it does. However, that requires me to test if the current thread already holds the lock—is there a way to do that?
Looking at the man page for pthread_rwlock_wrlock(), I see it says:
If successful, the pthread_rwlock_wrlock() function shall return zero; otherwise, an error number shall be returned to indicate the error.
[…]
The pthread_rwlock_wrlock() function may fail if:
EDEADLK The current thread already owns the read-write lock for writing or reading.
As I read it, EDEADLK is never used to indicate chains involving multiple threads waiting for each other’s resources (and from my observations, such deadlocks indeed seem to result in a freeze rather than EDEADLK). It seems to indicate exclusively that the thread is requesting a resource already held by the current thread, which is the condition I want to test for.
If I have misunderstood the documentation, please let me know. Otherwise the solution would be to simply call pthread_rwlock_wrlock(). One of the following should happen:
It blocks because another thread holds the resource. When we get to run again, we will hold the lock. Business as usual.
It returns zero (success) because we have just acquired the lock (which we didn’t hold before). Business as usual.
It returns EDEADLK because we are already holding the lock. No need to reacquire, but we might want to consider this when we release the lock—that depends on the code in question, see below
It returns some other error, indicating something has truly gone wrong. Same as with every other lock operation.
It may make sense to keep track of the number of times we have acquired the lock and got EDEADLK. Taking from Gil Hamilton’s answer, the lock depth would work for us:
Reset the lock depth to 0 when we have acquired a lock.
Increase the lock depth by 1 each time we get EDEADLK.
Match each attempt to acquire the lock with the following: If lock depth is 0, release the lock. Else decrease the lock depth.
This should be thread-safe without further synchronization, as the lock depth is effectively protected by the lock it refers to (we touch it only while holding the lock).
Caveat: if the current thread already holds the lock for reading (and no others do), this will also report it as being “already locked”. Further tests will be needed to determine if the currently held lock is indeed a write lock. If multiple threads, among them the current one, hold the read lock, I do not know if attempting to obtain a write lock will return EDEADLK or freeze the thread. This part needs some more work…
AFAIK, there's no easy way to accomplish what you're trying to do.
In linux, you can use the "recursive" mutex attribute to achieve your purpose (as shown here for example: https://stackoverflow.com/a/7963765/1076479), but this is not "posix"-portable.
The only really portable solution is to roll your own equivalent. You can do that by creating a data structure containing a lock along with your own thread index (or equivalent) and an ownership/recursion count.
CAVEAT: Pseudo-code off the top of my head
Recursive lock:
// First try to acquire the lock without blocking...
if ((err = pthread_mutex_trylock(&mystruct.mutex)) == 0) {
// Acquire succeeded. I now own the lock.
// (I either just acquired it or already owned it)
assert(mystruct.owner == my_thread_index || mystruct.lock_depth == 0);
mystruct.owner = my_thread_index;
++mystruct.lock_depth;
} else if (mystruct.owner == my_thread_index) {
assert(err == EBUSY);
// I already owned the lock. Now one level deeper
++mystruct.lock_depth;
} else {
// I don't own the lock: block waiting for it.
pthread_mutex_lock(&mystruct.mutex);
assert(mystruct.lock_depth == 0);
}
On the way out, it's simpler, because you know you own the lock, you only need to determine whether it's time to release it (i.e. the last unlock). Recursive unlock:
if (--mystruct.lock_depth == 0) {
assert(mystruct.owner == my_thread_index);
// Last level of recursion unwound
mystruct.owner = -1; // Mark it un-owned
pthread_mutex_unlock(&mystruct.mutex);
}
I would want to add some additional checks and assertions and significant testing before trusting this too.

Is there something bad will happend when construct multi level dispatchQueue

Snippet 1
let workerQueue = DispatchQueue(label: "foo")
workderQueue.async {
#code
DispatchQueue.main.async {
#code
workerQueue.async {
#code
}
}
}
Snippet 2
let workerQueue = DispatchQueue(label: "foo")
DispatchQueue.main.async {
#code
workerQueue.async {
#code
DispatchQueue.main.async {
#code
}
}
}
Is it ok to write code like snippet 1 or snippet 2 ? Will the main thread be blocked?
No, there’s nothing inherently “bad” with these patterns.
That having been said, the typical pattern is:
workerQueue.async {
// do something computationally intensive
DispatchQueue.main.async {
// update UI and/or model
}
}
And this is motivated by “I have something sufficiently intensive that I don’t want it running on the main queue (and adversely affecting the UX), but when I’m done, I need to update my UI and/or the model.”
It’s pretty rare that you also have a further level of nesting that says “and when I’m done updating the UI, I need to dispatch something else back to my same worker queue”, as shown in your first example. If you have a practical example of that, perhaps you can share it with us, as there might be more elegant ways of refactoring that to avoid a “tower” of nested dispatches, which can start to render the code a little hard to follow.
In your second example, where you’re dispatching to the main thread first is also a bit atypical. (Yes, we occasionally have to do that, but it’s less common.) I guess you’re presuming you’re already on some other thread (though not always). If that’s the case, where the code is expecting you to be on a particular thread, you might want to make that assumption explicit, e.g.:
func foo() {
dispatchPrecondition(condition: .onQueue(workerQueue))
// do some stuff that should be on the `workerQueue`
DispatchQueue.main.async {
// update UI, etc.
...
}
}
Bottom line, there’s absolutely no problem with an arbitrary level of nesting, especially if doing it with async ... doing this with sync can invite deadlock problems if you’re not careful. But from a practical “can future programmers read this code and clearly deduce what the resulting behavior is going to be”, you will often want to constrain this so it’s not too confusing.
As a practical example I might be doing something on some dedicate functional queue (e.g. a database access queue or an image processing queue), and I might need to use another synchronization queue to ensure thread-safe access, and I might need to do UI updates on the main queue. But I don’t generally have this tower of three levels of queues, but, for example, I encapsulate these various levels to avoid confusion (e.g. I have a reader-writer generic that encapsulates the details of that concurrent queue I use for thread-safe access), and my code avoids complicated intermingling different types of dispatch queues in any given method. At any particular level of abstraction I’m trying to avoid too many different queue types at one time.
You only need to execute code on desired thread, if you are on some another thread.
For example, Since by default app runs on main thread. But if a task runs on Background thread and modifies UI element within itself, then it should be enclosed in main thread.
some_background/other_thread_task {
DispatchQueue.main.async {
//UI Update
self.myTableView.reloadData()
}
}
Both your snippets are the same structure. That structure is totally normal and is exactly how to switch threads.

Is a block in Objective-C always guaranteed to capture a variable?

Are there any conditions in Objective-C (Objective-C++) where the compiler can detect that a variable capture in a block is never used and thus decide to not capture the variable in the first place?
For example, assume you have an NSArray that contains a large number of items which might take a long time to deallocate. You need to access the NSArray on the main thread, but once you're done with it, you're willing to deallocate it on a background queue. The background block only needs to capture the array and then immediately deallocate. It doesn't actually have to do anything with it. Can the compiler detect this and, "erroneously", skip the block capture altogether?
Example:
// On the main thread...
NSArray *outgoingRecords = self.records;
self.records = incomingRecords;
dispatch_async(background_queue, ^{
(void)outgoingRecords;
// After this do-nothing block exits, then outgoingRecords
// should be deallocated on this background_queue.
});
Am I guaranteed that outgoingRecords will always be captured in that block and that it will always be deallocated on the background_queue?
Edit #1
I'll add a bit more context to better illustrate my issue:
I have an Objective-C++ class that contains a very large std::vector of immutable records. This could easily be 1+ million records. They are basic structs in a vector and accessed on the main thread to populate a table view. On a background thread, a different set of database records might be read into a separate vector, which could also be quite large.
Once the background read has occurred, I jump over to the main thread to swap Objective-C objects and repopulate the table.
At that point, I don't care at all about the contents of the older vector or its parent Objective-C class. There's no fancy destructors or object-graph to teardown, but deallocating hundreds of megabytes, maybe even gigabytes of memory is not instantaneous. So I'm willing to punt it off to a background_queue and have the memory deallocation occur there. In my tests, that appears to work fine and gives me a little bit more time on the main thread to do other stuff before 16ms elapses.
I'm trying to understand if I can get away with simply capturing the object in an "empty" block or if I should do some sort of no-op operation (like call count) so that the compiler cannot optimize it away somehow.
Edit #2
(I originally tried to keep the question as simple as possible, but it seems like it's more nuanced then that. Based on Ken's answer below, I'll add another scenario.)
Here's another scenario that doesn't use dispatch_queues but still uses blocks, which is the part I'm really interested in.
id<MTLCommandBuffer> commandBuffer = ...
// A custom class that manages an MTLTexture that is backed by an IOSurface.
__block MyTextureWrapper *wrapper = ...
// Issue some Metal calls that use the texture inside the wrapper.
// Wait for the buffer to complete, then release the wrapper.
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> cb) {
wrapper = nil;
}];
In this scenario, the order of execution is guaranteed by Metal. Unlike the example above, in this scenario performance is not the issue. Rather, the IOSurface that is backing the MTLTexture is being recycled into a CVPixelBufferPool. The IOSurface is being shared between processes and, from what I can tell, MTLTexture does not appear to increase the useCount on the surface. My wrapper class does. When my wrapper class is deallocated, the useCount is decremented and the bufferPool is then free to recycling the IOSurface.
This is all working as expected but I end up with silly code like above just out of uncertainty whether I need to "use" the wrapper instance in the block to ensure it's captured or not. If the wrapper is deallocated before the completion handler runs, then the IOSurface will be recycled and the texture will get overwritten.
Edit to address question edits:
From the Clang Language Specification for Blocks:
Local automatic (stack) variables referenced within the compound
statement of a Block are imported and captured by the Block as const
copies. The capture (binding) is performed at the time of the Block
literal expression evaluation.
The compiler is not required to capture a variable if it can prove
that no references to the variable will actually be evaluated.
Programmers can force a variable to be captured by referencing it in a
statement at the beginning of the Block, like so:
(void) foo;
This matters when capturing the variable has side-effects, as it can
in Objective-C or C++.
(Emphasis added.)
Note that using this technique guarantees that the referenced object lives at least as long as the block, but does not guarantee it will be released with the block, nor by which thread.
There's no guarantee that the block submitted to the background queue will be the last code to hold a strong reference to the array (even ignoring the question of whether the block captures the variable).
First, the block may in fact run before the context which submitted it returns and releases its strong reference. That is, the code which called dispatch_async() could be swapped off the CPU and the block could run first.
But even if the block runs somewhat later than that, a reference to the array may be in an autorelease pool somewhere and not released for some time. Or there may be a strong reference someplace else that will eventually be cleared but not under you explicit control.

Clean JavaFX property listeners and bindings (memory leaks)

I haven't found a simple answer for these two questions:
do I have to remove a listener before deleting the property instance (the listener is not used anywhere else)?
BooleanProperty bool = new SimpleBooleanProperty();
bool.addListener(myListener);
bool.removeListener(myListener); // is it necessary to do this?
bool = null;
do I have to unbind a uni-directional bounded property before deleting the property instance?
BooleanProperty bool = new SimpleBooleanProperty();
bool.bind(otherBool);
bool.unbind(); // is it necessary to do this?
bool = null;
Case 1
Given that myListener "is not used anywhere else" and therefore I assume, a [method-] local variable, the answer is no. In the general case though, the answer is mostly a no but can sometimes be a yes.
As long as myListener is strongly reachable, then it will never become eligible for finalization and it will continue to consume memory. For example, this would be the case if myListener is a "normally" declared static variable (*all "normal" references in Java are strong references*). However, if myListener is a local variable, then the object will not be reachable anymore after the return of the current method call and bool.removeListener(myListener) is a bit meaningless over-engineering. Both the observer and the Observable goes out of scope and will eventually be finalized. A quote from my own blog post about this answer might paint a better picture:
It doesn’t matter if the box know about the cat inside of it, if you
throw the box into the ocean. If the box isn't reachable, nor is the
cat.
Theory
To fully understand the situation here, we have to remind ourselves of the life-cycle of a Java object (source):
An object is strongly reachable if it can be reached by some thread
without traversing any reference objects. A newly-created object is
strongly reachable by the thread that created it. [..] An object is
weakly reachable if it is [not] strongly [..] reachable but can be
reached by traversing a weak reference. When the weak references to a
weakly-reachable object are cleared, the object becomes eligible for
finalization.
In the case of static variables, these will always be accessible as long as the class is loaded, thus reachable. If we didn't want a static reference to be the one that hinder the garbage collector to do his job, then we could declare the variable to use a WeakReference instead. JavaDoc says:
Weak reference objects [..] do not prevent their referents from being
made finalizable, finalized, and then reclaimed. [..] Suppose that the
garbage collector determines at a certain point in time that an object
is weakly reachable. At that time it will atomically clear all weak
references to that object [..]. At the same time it will declare all
of the formerly weakly-reachable objects to be finalizable.
Explicit management
For illustration, let's assume that we write a JavaFX space simulation game. Whenever an Observable planet moves into the view of a spaceship observer, the game engine register the spaceship with the planet. It is quite apparent that whenever the planet goes out of view, the game engine should also remove the spaceship as an observer of the planet by using Observable.removeListener(). Otherwise, as the spaceship continues to fly through space, memory will leak. Eventually, the game cannot handle five billion observed planets and it will crash with an OutOfMemoryError.
Do note that for the vast majority of JavaFX listeners and event handlers, their life-cycle is parallel to that of their Observable so the application developer has nothing to worry about. For example, we might construct a TextField and register with the text field's textProperty a listener that validate user input. As long as the text field sticks around, we want the listener to stick around. Sooner or later, the text field is not used anymore and when he is garbage collected, the validation listener is also garbage collected.
Automatic management
To continue on the space simulation example, assume that our game has limited multiplayer support and all the players need to observe each other. Perhaps each player keep a local score board of kill metrics or perhaps they need to observe broadcasted chat messages. The reason is not the important point here. What would happen when a player quit the game? Clearly, if the listeners are not explicitly managed (removed), then the player who quit will not become eligible for finalization. The other player's will keep a strong reference to the offline player. Explicit removal of the listeners would still be a valid option and probably the most preferred choice for our game, but let's say that it feels a bit obtrusive and we want to find a more slick solution.
We know that the game engine keep strong references to all players online, for as long as they are online. So we want the spaceships to listen for changes or events of each other only for as long as the game engine keep the strong references. If you read the "theory" section, then surely a WeakReference sounds like a solution.
However, just wrapping something in a WeakReference is not the entire solution. It seldom is. It is true that when the last strong reference to the "referent" is set to null or otherwise become unreachable, the referent will be eligible for garbage collection (assuming that the referent cannot be reached using a SoftReference). But the WeakReference is still hanging around. The application developer need to add some plumbing so that the WeakReference itself is removed from the data structure he was put in. If not, then we might have reduced the severity of the memory leak but a memory leak will still be present because dynamically added weak references consume memory too.
Lucky for us, JavaFX added interface WeakListener and class WeakEventHandler as a mechanism for "automatic removal". The constructors of all related classes accept the real listener/handler as provided by client code, but they store the listener/handler using a weak reference.
If you look at the JavaDoc of WeakEventHandler, you'll notice that the class implement EventHandler, so the WeakEventHandler can be used wherever an EventHandler is expected. Likewise, a known implementation of a WeakListener can be used wherever an InvalidationListener or a ChangeListener is expected.
If you look into the source code of WeakEventHandler, you'll notice that the class is basically only a wrapper. When his referent (the real event handler) is garbage collected, the WeakEventHandler "stop working" by not doing anything at all when WeakEventHandler.handle() is called. The WeakEventHandler doesn't know about which object he has been hooked up with, and even if he did, the removal of an event handler is not homogeneous. All known implementing classes of WeakListener has a competitive advantage though. When their callbacks are invoked, they are implicitly or explicitly provided a reference to the Observable they are registered with. So when the referent of a WeakListener is garbage collected, eventually the WeakListener implementation will make sure that the WeakListener itself is removed from the Observable.
If it is isn't already clear, the solution for our space simulation game would be to let the game engine use strong references to all online spaceships. When a spaceship goes online, all other online spaceships are registered with the new player using a weak listener such as WeakInvalidationListener. When a player goes offline, the game engine remove his strong reference to the player and the player will become eligible for garbage collection. The game engine doesn't have to bother about explicit removal of the offline player as a listener of the other players.
Case 2
No. To better understand what I'll say next, please read my case 1 answer first.
BooleanPropertyBase store a strong reference to otherBool. This in itself does not cause otherBool to always be reachable and thus potentially cause a memory leak. When bool becomes unreachable, then so do all its stored references (assuming they are not stored anywhere else).
BooleanPropertyBase also works by adding itself as an Observer of the property you bind it to. However, it does so by wrapping itself in a class that works almost exactly like the WeakListeners described in my case 1 answer. So once you nullify bool, it will be only a matter of time before it is removed from otherBool.
I completely agree with the case 1 answer, but the case 2 is a bit more tricky. The bool.unbind() call is necessary. If ommitted, it does cause a small memory leak.
If you run the following loop, the application will eventually run out of memory.
BooleanProperty p1 = new SimpleBooleanProperty();
while(true) {
BooleanProperty p2 = new SimpleBooleanProperty();
p2.bind(p1)
}
The BooleanPropertyBase, intenally, does not use a real WeakListener (an implementation of the WeakListener interface), it is using a half-baked solution. All the "p2" instances get eventually garbage-collected, but a listener holding an empty WeakReference remains in the memory forever for each "p2". The same holds for all properties, not only BooleanPropertyBase. It's explained here in detail, and they say it is fixed in Java 9.
In most cases, you do not notice this memory leak, because it leaves only a few dozen bytes for every binding that has not been unbound. But in some cases it caused me real trouble. An good example are table cells of a table that gets frequently updated. The cells then re-bind to different properties all the time, and these left-overs in the memory accumulate quickly.

slow memory release (refcounted structure) - Is my workaround a good way?

in my program i can load a Catalog: ICatalog
a Catalog here contains a lot of refcounted structures (Icollections of IItems, IElements, IRules, etc.)
when I want to change to another catalog,
I load a new Catalog
but the automatic release of the previous ICatalog instance takes time, freezing my application for 2 second or more.
my question is :
I want to defer the release of the old (and no more used) ICatalog instance to another thread.
I've not tested it already, but I intend to create a new thread with :
ErazerThread.OldCatalog := Catalog; // old catalog refcount jumps to 2
Catalog := LoadNewCatalog(...); // old catalog refcount =1
ErazerThread.Execute; //just set OldCatalog to nil.
this way, I expect the release to occur in the thread, and my application not
beeing freezed anymore.
Is it safe (and good practice) ?
Do you have examples of existing code already perfoming release with a similar method ?
I would let such thread block on some threadsafe queue(*), and push the interfaces to release into that queue as iunknowns.
Note however that if the releasing touches a lock that your memory manager uses (like a global heapmanager lock), then this is futile, since your mainthread will block on the first heapmanager access.
With a heapmanager with per thread pools, allocating many items in one thread and releasing it in a different thread might frustrate coalescing and reuse of (small) blocks algorithms.
I still think the way you describe is generally sound when implemented properly. But
this is from a theoretic perspective to show that there might be a link from the 2nd thread to the mainthread via the heapmanager.
(*) Simplest way is to add it to a tthreadlist and use tevent to signal that an element was added.
That looks OK, but don't call the thread's Execute method directly; that will run the thread object's code in the current thread instead of the one that the thread object creates. Call Start or Resume instead.

Resources