Mentioned in #19142, which removed the boost::interruption_point()
in ThreadImport().
init: use std::thread for ThreadImport() #19197
pull fanquake wants to merge 1 commits into bitcoin:master from fanquake:thread_import_no_boost changing 1 files +5 −3-
fanquake commented at 5:37 AM on June 7, 2020: member
- fanquake added the label Refactoring on Jun 7, 2020
-
hebasto commented at 6:18 AM on June 7, 2020: member
Concept ACK.
-
in src/init.cpp:1856 in aeb100f79e outdated
1851 | @@ -1853,7 +1852,8 @@ bool AppInitMain(const util::Ref& context, NodeContext& node) 1852 | vImportFiles.push_back(strFile); 1853 | } 1854 | 1855 | - threadGroup.create_thread([=, &chainman] { ThreadImport(chainman, vImportFiles); }); 1856 | + std::thread import(&TraceThread<std::function<void()>>, "loadblk", [=, &chainman]{ ThreadImport(chainman, vImportFiles); }); 1857 | + import.detach();
hebasto commented at 6:55 AM on June 7, 2020:nit: The
AppInitMain()is a way large function. Could the scope of theimportvariable be limited by a block?hebasto approvedhebasto commented at 6:59 AM on June 7, 2020: memberACK aeb100f79ec6ff816ee26344b4eef70001dd51a6, tested on Linux Mint 19.3 (x86_64) with
-reindexcommand-line option and thread monitoring via htop.hebasto commented at 7:12 AM on June 7, 2020: memberKeep testing and the second instance of "loadblk" thread appears:

Is it ok?
UPDATE: the same behavior observed on master, therefore it seems does not related to this PR changes. Going to submit a dedicated issue.
MarcoFalke commented at 10:26 AM on June 7, 2020: memberwhy is is ok to not wait for the thread to exit (join) before shutdown?
sipa commented at 4:28 PM on June 7, 2020: member@MarcoFalke AFAIK, there is no problem with that. The application won't quit until all its threads have terminated.
MarcoFalke commented at 4:34 PM on June 7, 2020: memberWhat 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?
donaloconnor commented at 4:57 PM on June 7, 2020: contributor@MarcoFalke AFAIK, there is no problem with that. The application won't quit until all its threads have terminated.
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?
#include <thread> #include <chrono> #include <iostream> using namespace std::chrono_literals; struct Destruct { ~Destruct() { std::cout << "Dtor called" << std::endl; } }; void ThreadProc() { Destruct d; std::this_thread::sleep_for(1s); } int main(int argc, char* argv[]) { std::cout << "Hello" << std::endl; std::thread t(ThreadProc); //t.join(); t.detach(); std::cout << "Bye" << std::endl; return 0; }Output is Hello,Bye instead of Hello,Dtor called,Bye. Edit: above output wouldn't happen anyway. - but I'm wondering if dtor really gets called or not. I'll do more research.
sipa commented at 5:05 PM on June 7, 2020: member@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.
laanwj commented at 2:35 PM on June 9, 2020: memberConcept ACK.
@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.
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
detachis acceptable, that is the treads spawning child processes for notification that run free)fanquake force-pushed on Jun 12, 2020fanquake commented at 7:47 AM on June 12, 2020: memberPushed a
.detach()-less change.in src/init.cpp:221 in 2aca26d5dd outdated
215 | @@ -214,8 +216,9 @@ void Shutdown(NodeContext& node) 216 | StopTorControl(); 217 | 218 | // After everything has been shut down, but before things get flushed, stop the 219 | - // CScheduler/checkqueue threadGroup 220 | + // CScheduler/checkqueue, threadGroup and load block thread. 221 | if (node.scheduler) node.scheduler->stop(); 222 | + g_load_block.join();
donaloconnor commented at 7:59 AM on June 12, 2020:I think it might be safer to check if the thread is joinable before joining in case this path is reached after some initialization failure when the thread may not have started.
fanquake commented at 8:06 AM on June 12, 2020:Thanks, I've added that.
83fd3a6d73init: use std::thread for ThreadImport()
Mentioned in #19142, which removed the boost::interruption_point() in ThreadImport().
fanquake force-pushed on Jun 12, 2020donaloconnor commented at 8:08 AM on June 12, 2020: contributorACK 83fd3a6
in src/init.cpp:155 in 83fd3a6d73
151 | @@ -152,6 +152,8 @@ NODISCARD static bool CreatePidFile() 152 | 153 | static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle; 154 | 155 | +static std::thread g_load_block;
MarcoFalke commented at 11:22 AM on June 12, 2020: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
ThreadImportshould be moved to validation because it is purely validation related. Init shouldn't need to know how to load blocks from disk, etc... Note thatLoadMempoolis 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?
laanwj commented at 3:33 PM on June 16, 2020: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.
MarcoFalke commented at 4:22 PM on June 16, 2020: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);
fanquake commented at 5:26 AM on June 19, 2020: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.
laanwj commented at 3:34 PM on June 16, 2020: memberCode review ACK 83fd3a6d73eee452dc5141bdf6826da62d7b2dbd
MarcoFalke commented at 4:22 PM on June 16, 2020: memberACK 83fd3a6d73eee452dc5141bdf6826da62d7b2dbd
hebasto approvedhebasto commented at 12:15 PM on June 18, 2020: memberACK 83fd3a6d73eee452dc5141bdf6826da62d7b2dbd, 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.
fanquake merged this on Jun 19, 2020fanquake closed this on Jun 19, 2020fanquake deleted the branch on Jun 19, 2020sidhujag referenced this in commit 3598bbfdba on Jul 7, 2020fanquake referenced this in commit f538c25cd4 on Jan 29, 2021fanquake referenced this in commit be7065623a on Feb 2, 2021fanquake referenced this in commit e3341dfaf7 on Feb 2, 2021MarcoFalke referenced this in commit 63984b38f0 on Apr 2, 2021deadalnix referenced this in commit ae09ca09e4 on Jul 23, 2021DrahtBot locked this on Feb 15, 2022
This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-14 12:14 UTC
More mirrored repositories can be found on mirror.b10c.me