-
Notifications
You must be signed in to change notification settings - Fork 37.8k
init: use std::thread for ThreadImport() #19197
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
Conversation
Concept ACK. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK aeb100f, tested on Linux Mint 19.3 (x86_64) with -reindex
command-line option and thread monitoring via htop.
src/init.cpp
Outdated
std::thread import(&TraceThread<std::function<void()>>, "loadblk", [=, &chainman]{ ThreadImport(chainman, vImportFiles); }); | ||
import.detach(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: The AppInitMain()
is a way large function. Could the scope of the import
variable be limited by a block?
why is is ok to not wait for the thread to exit (join) before shutdown? |
@MarcoFalke AFAIK, there is no problem with that. The application won't quit until all its threads have terminated. |
What I mean is that during shutdown we assume the chain clients don't receive (let's say) block connected signals anymore because they are already flushed. After this change, it is (theoretically, I haven't checked) possible that ThreadImport generates events that will be sent to objects that can't handle them or that ThreadImport reads from objects that have been deleted. Am I missing something obvious? |
I thought that once main returns, any detached threads will not be waited on and stack unwinding does not occur risking danger of uncalled dtors. I tried a sample here and it seems to be the case?
Output is Hello,Bye instead of Hello,Dtor called,Bye. |
@donaloconnor I would certainly have expected the code above to sleep 1 s before exiting, so it does seem I'm wrong. @MarcoFalke That's a good point. It seems we'll need to keep the std::thread object around somehow, and join it in the right order at shutdown. |
Concept ACK.
Yes. It needs to be join-ed on shutdown to make sure it has terminated before tearing down validation-related data structures. Detach is not safe for a thread like this. (there's only one use where using |
aeb100f
to
2aca26d
Compare
Pushed a |
Mentioned in bitcoin#19142, which removed the boost::interruption_point() in ThreadImport().
2aca26d
to
83fd3a6
Compare
ACK 83fd3a6 |
@@ -152,6 +152,8 @@ NODISCARD static bool CreatePidFile() | |||
|
|||
static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle; | |||
|
|||
static std::thread g_load_block; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really like adding more and more globals to init. Ideally init should be a slim file with only calls to other modules to start/stop. Longer term ThreadImport
should be moved to validation because it is purely validation related. Init shouldn't need to know how to load blocks from disk, etc... Note that LoadMempool
is also in validation.
Moreover, with assumeutxo, thus multiple chainstates, I could imagine that a reindex/import can be done in the background chainstate for additional efficiency. Having init to deal with even more chainstate related logic would feel wrong.
What do you think about making this thread a member of the chainstate manager?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the other hand this was a hidden global before, a part of threadGroup
(which can hopefully go away soon!). I don't think this PR makes anything worse.
I think your longer-term solution makes sense, but I'm not sure it needs to be done here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree that it doesn't make anything worse, but it could be slightly better with a trivial diff.
diff --git a/src/init.cpp b/src/init.cpp
index 8d9566edc3..984f6b2034 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -152,8 +152,6 @@ NODISCARD static bool CreatePidFile()
static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
-static std::thread g_load_block;
-
static boost::thread_group threadGroup;
void Interrupt(NodeContext& node)
@@ -218,7 +216,7 @@ void Shutdown(NodeContext& node)
// After everything has been shut down, but before things get flushed, stop the
// CScheduler/checkqueue, threadGroup and load block thread.
if (node.scheduler) node.scheduler->stop();
- if (g_load_block.joinable()) g_load_block.join();
+ if (node.chainman && node.chainman->m_load_block.joinable()) node.chainman->m_load_block.join();
threadGroup.interrupt_all();
threadGroup.join_all();
@@ -1844,7 +1842,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node)
vImportFiles.push_back(strFile);
}
- g_load_block = std::thread(&TraceThread<std::function<void()>>, "loadblk", [=, &chainman]{ ThreadImport(chainman, vImportFiles); });
+ chainman.m_load_block = std::thread(&TraceThread<std::function<void()>>, "loadblk", [=, &chainman]{ ThreadImport(chainman, vImportFiles); });
// Wait for genesis block to be processed
{
diff --git a/src/validation.h b/src/validation.h
index e403bcb51a..9764a7aaca 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -783,6 +783,7 @@ private:
friend CChain& ChainActive();
public:
+ std::thread m_load_block;
//! A single BlockManager instance is shared across each constructed
//! chainstate to avoid duplicating block metadata.
BlockManager m_blockman GUARDED_BY(::cs_main);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. I'll take care of the suggestions, adding to chainman and thread renaming, in some followup changes. I just wanted to get it out of the Boost thread group here.
Code review ACK 83fd3a6 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 83fd3a6
@@ -152,6 +152,8 @@ NODISCARD static bool CreatePidFile() | |||
|
|||
static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle; | |||
|
|||
static std::thread g_load_block; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree that it doesn't make anything worse, but it could be slightly better with a trivial diff.
diff --git a/src/init.cpp b/src/init.cpp
index 8d9566edc3..984f6b2034 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -152,8 +152,6 @@ NODISCARD static bool CreatePidFile()
static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
-static std::thread g_load_block;
-
static boost::thread_group threadGroup;
void Interrupt(NodeContext& node)
@@ -218,7 +216,7 @@ void Shutdown(NodeContext& node)
// After everything has been shut down, but before things get flushed, stop the
// CScheduler/checkqueue, threadGroup and load block thread.
if (node.scheduler) node.scheduler->stop();
- if (g_load_block.joinable()) g_load_block.join();
+ if (node.chainman && node.chainman->m_load_block.joinable()) node.chainman->m_load_block.join();
threadGroup.interrupt_all();
threadGroup.join_all();
@@ -1844,7 +1842,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node)
vImportFiles.push_back(strFile);
}
- g_load_block = std::thread(&TraceThread<std::function<void()>>, "loadblk", [=, &chainman]{ ThreadImport(chainman, vImportFiles); });
+ chainman.m_load_block = std::thread(&TraceThread<std::function<void()>>, "loadblk", [=, &chainman]{ ThreadImport(chainman, vImportFiles); });
// Wait for genesis block to be processed
{
diff --git a/src/validation.h b/src/validation.h
index e403bcb51a..9764a7aaca 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -783,6 +783,7 @@ private:
friend CChain& ChainActive();
public:
+ std::thread m_load_block;
//! A single BlockManager instance is shared across each constructed
//! chainstate to avoid duplicating block metadata.
BlockManager m_blockman GUARDED_BY(::cs_main);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 83fd3a6, I have reviewed the code and it looks OK, I agree it can be merged.
While this code is touched already, the "loadblk" thread could be renamed to "loadblocks" (10 characters from 13 allowed) or "importblocks" (12 characters) for readability.
83fd3a6 init: use std::thread for ThreadImport() (fanquake) Pull request description: [Mentioned](bitcoin#19142 (comment)) in bitcoin#19142, which removed the `boost::interruption_point()` in `ThreadImport()`. ACKs for top commit: hebasto: ACK 83fd3a6, I have reviewed the code and it looks OK, I agree it can be merged. donaloconnor: ACK 83fd3a6 laanwj: Code review ACK 83fd3a6 MarcoFalke: ACK 83fd3a6 Tree-SHA512: 0644947d669feb61eed3a944012dad1bd3dd75cf994aa2630013043c213a335b162b63e20aa37e0997740d8e3a3ec367b660b5196007a09e13f0ac455b36c821
This is a diff of Marcos from bitcoin#19197, which probably should have just been used at the time. After this change, and bitcoin#21016, we'll have no more global thread(Group)s hanging out in init. Co-authored-by: MarcoFalke <falke.marco@gmail.com>
This is a diff of Marcos from bitcoin#19197, which probably should have just been used at the time. After this change, and bitcoin#21016, we'll have no more global thread(Group)s hanging out in init. Co-authored-by: MarcoFalke <falke.marco@gmail.com>
This is a diff of Marcos from bitcoin#19197, which probably should have just been used at the time. After this change, and bitcoin#21016, we'll have no more global thread(Group)s hanging out in init. Co-authored-by: MarcoFalke <falke.marco@gmail.com>
This is a diff of Marcos from bitcoin#19197, which probably should have just been used at the time. After this change, and bitcoin#21016, we'll have no more global thread(Group)s hanging out in init. Co-authored-by: MarcoFalke <falke.marco@gmail.com>
Summary: Mentioned in [[bitcoin/bitcoin#19142 | core#19142]], which removed the boost::interruption_point() in ThreadImport(). This is a backport of [[bitcoin/bitcoin#19197 | core#19197]] Test Plan: `ninja all check-all` Reviewers: #bitcoin_abc, deadalnix Reviewed By: #bitcoin_abc, deadalnix Differential Revision: https://reviews.bitcoinabc.org/D9833
Mentioned in #19142, which removed the
boost::interruption_point()
in
ThreadImport()
.