-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Thread-safe sf::err() #1724
base: 2.6.x
Are you sure you want to change the base?
Thread-safe sf::err() #1724
Conversation
@dec05eba if you find the time, could you check if this branch would also fix the problem you had? |
@Bromeon Confirmed that the crash is gone in this branch |
Thank you for testing! @SFML Team:
|
Does anyone have a good idea how to address this without memory leak? |
0842462
to
cfdba14
Compare
Experimented a bit more with this.
At this point all that is quite hacky, but so are the rules of C++ global variables and initialization order. I'm only wondering if we shouldn't just leave everything as-is and use a mutex. But let's see how it works out. Now we have a small example code for testing, but I don't get it to work -- not even the version that the issue author @dec05eba said would be OK. So I'm stuck and it would be nice if someone else could also look into it. Reproducing code (?)I used the one @dec05eba provided here, just changed the array to a vector and made the variables local. For some reason I always get a stack overflow (in both my commits and the original SFML version). #include <SFML/Graphics/Image.hpp>
#include <thread>
int main()
{
const int num_images = 3;
const std::string image_paths[3] = { "working-image.png", "non-existing-image.png", "Tennis.cpp" };
const int num_threads = 4;
std::vector<std::thread> threads;
for(int i = 0; i < num_threads; ++i) {
threads.emplace_back([&]() {
while(true) {
for(int i = 0; i < num_images; ++i) {
sf::Image image;
image.loadFromFile(image_paths[i]);
}
}
});
}
std::this_thread::sleep_for(std::chrono::seconds(10000000));
return 0;
} |
Any feedback? |
My opinion is that this change just shifts the problem from one place to another. Global initialization was/is/will always be a tricky subject in C++. While the problem has gotten less bad (yes... it still isn't good) with modern C++ (e.g. Over the years I have just trained myself to not access any non-POD, non-zero-initializable data that lives in namespace scope in my own code before In the current changeset, I haven't evaluated the effort required, but I think instead of piling one workaround on top of another, we should just adopt air-tight habits and avoid indirect calls to |
The thing is, we have two issues at hand: global initialization and multi-threaded access. If we use a global pointer that holds the lazy-initialized book-keeping logic, we run into the "who accesses first" problem. If two But otherwise I agree that it's ugly, and I wish C++ had more idiomatic ways to address this. Ultimately it looks like all possible implementations are just best-effort and have certain shortcomings, as such we might as well argue that fixing the common case (multithreaded TLDR: maybe we can trade off a "works in 95% of cases" problem with a "works in 99.5%" one. |
If most of the complexity just comes from allowing usage in a global scope, then I too would say, this shouldn't really be done. |
This is not the case here. If you look at the description of the original issue #1711 and the linked example, you see that the code is inside The problem is in the title: The global init issue is just part of the attempt to fix it. If I can rely on the assumption that no SFML code (i.e. any |
So, how do you want me to implement this? A discussed, I can go with the assumption that no SFML code (i.e.
Is the assumption always valid? Probably not. |
Could I get some feedback on this? I would say we go with the last suggestion -- assumption no |
If you think it's important enough for 2.6, then lets add it there. For me personally, any solution that improves the situation, especially for multi-threading, seems okay. |
As mentioned further above, that's not the issue I'm primarily trying to solve -- we have a race condition, when using SFML objects only in We can just fix the cases where objects are used in |
Of course it is, just click "edit" at the top and there you can change it. Of course need to make sure not to include any changes from master |
I think it's a lot easier to just make a decision to go one way, make assumptions that seem plausible and then based on that having a discussion, than to try and brain storm solutions on a GitHub issue. 😄 |
Very naive approach for fixing second problem in #1711.
sf::Err
is not thread-safe, and since it's used as a global logger across many different classes, this can quickly lead to problems when the user doesn't have a single-threaded SFML application.This implementation is not ready for merging, we need to discuss at least:
sf::ThreadLocalPtr
should be used properly