For safety reasons, a library I am working on has to determine owning process stages. Precise determination is not required but something like before/after main, before/after multithreading is enabled?
Something like std::atexit but for the startup?
The best idea I have is to create a class that will set a mark and statically initialize it with the highest possible init priority. I hope there are some commonly used means.
#include <iostream>
namespace test {
static bool flag;
class Check {
public:
Check(char const* name) : name_(name), flag_val_(flag) {}
void Print() {
std::cout << name_ << ": flag: " << flag_val_ << "\n";
}
private:
char const* name_;
bool flag_val_;
};
class Set {
public:
Set() {
flag = true;
}
};
static Check late_check __attribute__((init_priority(10000))) ("late check");
static Set set __attribute__((init_priority(2000)));
static Check early_check __attribute__((init_priority(1000))) ("early check");
} // namespace test
int main(int, char**) {
test::early_check.Print();
test::late_check.Print();
return 0;
}
Update: it seems that clarification is necessary I do not need to impose any changes on any library initialization. All I have to do different initialization steps depending upon whether main() is already called. And it does not have to be precise I am ok to know that the main is about to be called.
I will have a "Set" class from above setting the static with max init-priority then My App constructor will do different things depending upon flag its value
App.h:
------
class App { public: App(); ...};
App.cpp:
--------
static bool flag;
class Set { Set() { flag = true; }};
static Set set __attribute__((init_priority(65535)));
App::App() { if (flag) DoLateInit() else DoEarlyInit(); }
Client1.cpp:
-----------
static App myStaticApp;
Client2.cpp:
------------
App* myDynamicApp = new App;
Update2:
It seems that the only viable solution was provided in the comments by @johnfilleau: make the library user aware of the requirement to execute the function in question during initialization.
The alternative is to add more mutexes and a few atomics to enforce the safe behavior independently of the client app actions. This looked like an overkill initially but after the discussion, it seems like a fair trade.
How do I force my library to jump to the start of initialization order?
You can't.
Assume there is some magic technique by which your library can jump to the front of the initialization priority and jump to the end of deinitialization priority.
If your library has access to this magic technique, then you must assume that other libraries have access to the same magic technique.
If two libraries both try to jump to the start of initialization priority, then who wins?
This is an example of what Raymond Chen calls the "What if two programs did this?" problem.
Okay, so how do I solve it?
You solve this problem by clearly defining requirements:
If your library has some logic that must happen before anything else in the program, then the best you can do is the following:
Communicate your library's requirements to your users, and require that your users adhere to that requirement
Whatever you do, you must communicate these requirements to your library users, and the best you can do is to trust that they follow the rules.
"For Safety Reasons"
If your library truly has to start at a specific point in time "For Safety Reasons", then it's especially important that you do not hide these reasons and requirements from users.