Hi, hope everyone has good time with Zig like myself.
I would like to ask a very basic question regarding threading.
The short code below just works fine for my study purpose, but I would like to wait before it prints “Bye” in an idiomatic way - not calling the join twice as well as without the defer.
Maybe I can create a slice to hold the threads, and iterate over the slice, then call the join on a captured variable in the loop? What would you do?
Since I mostly learned/used high level languages like Go, I would like to learn how to handle some concurrency patterns. Not thread pool yet, but some baby steps first.
I don’t see anything wrong or “non-idiomatic” with your code.
Windows has WaitForMultipleObjects which allows joining for various threads at once, or wait for at least one to complete, but I don’t think Zig’s std exposes that.
The thread pool example seems like the one that I should learn little more.
The short array example seems like the one that fits what I am looking for right now.
Also I ended up writing something like this:
The one with the solution I picked.
Another one with the allocator (I am sure this is not the best way, but I am learning!).
I don’t see why you’d be joining threads[0] but not threads[1]. Also, if an error occurs, you’ll get a double join on threads[0], the one in the loop and the other in the errdefer.
That errdefer doesn’t make sense, it needs to be right after assigning to threads[0] so that the zero indexed thread gets joined in case the one indexed attempt to spawn a thread fails.
If it is below the assign to the one indexed thread you already know that the spawn was successful and the for loop takes care of both. The errdefer is so that you don’t forget joining the zero indexed one.
Don’t just reorder statements because it “looks cleaner”.
Also that whole block should be in its own scope so that the errdefer stops being active when the threads slice was successfully initialized. (you don’t want const thread2 = try ... to fail an trigger the errdefer way above because that would call join again.)
Also with thread2 and thread3 you aren’t handling error at all, just exiting the program without joining any potentially still fine threads.
Basically you aren’t handling failure well, you should study the nuance of the code in @dimdin’s and @dude_the_builder’s answers they are carefully written to handle failure at any point.
If you are unsure about error handling, force the error in different spots and see what happens, for example by just calling a failing function instead:
Thanks for correcting my mistake as well as detailed advises.
Yes, I blindly copied the answer (and happy it is running!), but you are right - I should understand what is the meaning for each line the order, especially in this low level programming environment.
Hope I can have better eyes when I bring another question.
Both threads are joined beforeBye is printed, every thread is joined if there’s an error, and there’s no code duplication between normal and error-handling code paths.
No, because “defer” only calls the “Join” after the main process. That was the question of how to solve this. It works without “defer”, but what happens in the case of an error?
@matklad is correct. Please refer to the official doc on how defer works. It is always called at the end of the innermost evclosing scope. In this case before printing Bye.
This curly brackets are the essential part of the trick. They establish the smaller scope forcing defer to be called at the end of this scope, before print Buy.