New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
iv_work_submit_work() might spawn a new child thread from incorrect parent #24
Comments
Hello! The
This restriction exists because of some of the reasons you mentioned. (This restriction wasn't enforced originally, and enforcing it now would involve breaking the ABI.) The locking in Allowing submission of work from arbitrary threads raises the question, as you alluded to, of where to run the completion handlers. Note that most of the complexity in Your first suggestion seems like it would prevent all current As to the second suggestion, where would you run the completion handler in this case? In the thread that created the work pool? How would you handle the case where thread A creates the work pool, and then thread B tries to enqueue work to the work pool while thread A tries to destroy the work pool? As to the third suggestion, where would you run the completion handler for a work item if this happens? (Would you not run it at all?) The removal of completion notification would obviate most of the current complexity in |
Hi Lennert and thank you for the detailed reply. very valid questions. I am giving this some more thought and come back to you. |
I usually start with reading the code instead of looking for documentation, but I may have to reconsider this about ivykis. Great library with great documentation. Thanks for that.
Got it.
Just a minor point, in my case it wasn't the completion handler that causes an issue, rather the "worker-thread-exit" machinery. In this specific case I wasn't using completion callbacks. Still in other cases syslog-ng uses them and they are very valid and useful part of the interface.
BTW: iv_work_pool_put() does not seem to wait for threads to exit. it signals that they should exit, but it does not seem to wait for them. I think this is the reason that we don't have an iv_deinit() at the end of our main(). But this is a side discussion and I might even miss something.
Let me explain the two separate use-cases of iv_work_pool in my context: 1. Async workers use-case:
Also, syslog-ng tracks the number of outstanding I/O tasks so we know when it is safe to exit, so we currently don't rely on iv_work_pool to do this for us. (probably because we have other threads as well, but I honestly don't remember). 2. Re-schedule work from a task use-case:
What I have found via experiments was that this handover between threads only improves performance as long as we don't overcommit the number of cores with threads. This means that I would like to limit parallel processing of messages to the number of cores in the system. And this is how we need to use the same iv_work_pool instance, its max_threads is set to the number of CPU cores (by default). Using a separate iv_work_pool-like object would not give me an easy way to limit the parallelism between I/O and CPU intensive processing. With that in mind, let me summarize what I would need, hopefully clarifying things a little:
With all that, I think the only needed change in iv_work_pool is being able to associate newly created threads with the main thread (e.g. the one owning iv_work_pool). The rest would just work. What do you think? |
Is this above something that would be worth supporting in your opinion? How else would you implement this? |
I have created a proof-of-concept branch here: https://github.com/bazsi/ivykis/tree/iv-work-pool-support-for-slave-work-items It currently uses an iv_event to wake up the main thread to launch a new worker thread, which should resolve the issue at the cost of some latency in starting up the worker (e.g. when the main thread is busy). What do you think? Should I clean that up or search for a completely different solution? thanks |
@buytenh any chance you could look into this in the near future? Thanks |
@bazsi Given that your change has merged, I think we can close this one now, right? |
Yup, absolutely. Closing. |
In syslog-ng, our main thread polls various sources and whenever there's a new I/O event, it submits this as work to a set of worker threads, an iv_work_pool instance.
This works great. I was about to reuse the same worker pool to submit job from another thread, i.e. not from the main thread.
In case there's no worker running at the time this 2nd thread submits a job to be executed, it will be spawned, as expected.
The problem happens when this worker thread wants to exit: since iv_thread_create() is called on-demand, from the 2nd thread, it is registered as a child of the 2nd thread, which means that iv_thread->dead is registered in the 2nd thread.
When the 2nd thread exits (earlier than the work_pool is destroyed), its state is freed (iv_deinit()), thus when the work-pool's thread exits, it's going to report back to a thread that does not exist at that point, causing a fatal error like this:
iv_fd_epoll_event_send: epoll_ctl returned error 9[Bad file descriptor]
Since the iv_work_pool_submit() seems to handle calls from multiple threads (as there's proper locking), I was under the assumption that it would work if I submit work from multiple threads.
I had multiple ideas how this could be handled, but I thought it's best to ask first:
This behaviour also surfaces in our main thread, where we don't call iv_deinit(), so that the ivykis state remains for as long as threads might be exiting, but I didn't want ad-hoc threads to not call iv_deinit()
what do you think?
The text was updated successfully, but these errors were encountered: