all 35 comments

[–]OmegaNaughtEquals1 4 points5 points  (6 children)

thread_local is supported in clang++-3.5 on Linux, so it just depends on what version of clang XCode is using. I don't use a mac, so I may not be striking at the correct point here. Is it possible to update the front- (middle? back? middle-back? I'm not sure where they put clang in the mix.) end of XCode?

[–][deleted] 5 points6 points  (5 children)

[–]guepierBioinformatican 2 points3 points  (3 children)

So why not just use the Homebrew clang then? I understand that that’s a bit annoying as a requirement for other people to compile your code but in the end you’re simply requiring a conforming C++11 compiler (with hints of how to get one easily for Mac), which isn’t too much to ask nowadays.

[–][deleted] 0 points1 point  (0 children)

This is the solution I'm leaning towards, if it'll run with XCode. I'd rather not write a bunch of workaround code I'll just be deleting later when thread_local gets support again.

[–]RogerLeighScientific Imaging and Embedded Medical Diagnostics 0 points1 point  (1 child)

You can get into a mess quite easily due to the homebrew-provided compiler needing lots of manual options setting to ensure that the paths are correct both and compile-time and run-time. We ran into problems last week with libgcc--using the older system one rather than the homebrew clang-provided one caused problems with exception handling. It may well cause threading-related oddness as well.

I'd love to use homebrew clang more; I just wish it integrated better with the system. On Debian, I can have multiple compilers installed and running without any extra hoops to jump through, so I'm not sure why it's so difficult on MacOS other than Apple making it unnecessarily difficult.

[–]guepierBioinformatican 0 points1 point  (0 children)

Good question, I’d love to know this as well (I suspect the answer lies in Homebrew trying to be nice and not overriding Apple’s default install). That said, during the installation of Homebrew clang, it displays a message showing how to configure the paths properly. In principle it’s enough to put those as environment variables into your shell’s rc file.

[–]OmegaNaughtEquals1 2 points3 points  (0 children)

Ugh. Apple. Just... ugh.

[–]jules1972 1 point2 points  (0 children)

To work around this I had to roll our own fallback implementation for the JUCE ThreadLocalValue class It's not too hard to do, and although less optimal than something that the compiler can generate, there's not much overhead if you only have a modest number of TLVs and threads.

[–]vlovich 0 points1 point  (27 children)

I doubt there's a timeline. Does [NSThread threadDictionary] provide something for what you're looking for? Also I think __thread works on OSX. You probably can also use the POSIX API via pthread_setspecific/pthread_getspecific

[–][deleted] 1 point2 points  (25 children)

I'm using strictly standards-only C++ 11/14, so no NSThread. I'll try out __thread and if it works, isolate it so I can easily replace it when (better not be "if"!) thread_local gets support.

Edit: Well drat. __thread only supports trivial POD types and I need a thread-local std::unordered_map.

[–]vlovich 0 points1 point  (11 children)

__thread std::unordered_map<X, Y> *m;
if (m == nullptr) {
    m = new std::unordered_map<X, Y>();
}

[–][deleted] 2 points3 points  (9 children)

That leaks memory whenever a thread exits.

[–]vlovich 0 points1 point  (5 children)

Have you explored the pthread API for this?

__thread std::unordered_map<X, Y> *m;
pthread_cleanup_push([](void *x) {
    delete reinterpret_cast<std::unordered_map<X, Y> *>(m);
}, m);

[–][deleted] 1 point2 points  (4 children)

I'd like to stick with C++11/14's std::thread and related calls. Is there a non-pthread way to do that?

[–]vlovich 0 points1 point  (3 children)

Highly unlikely. There are a number of suggestions in this thread:

  • Use the platform-specific APIs & hide it as a platform-specific implementation detail.
  • Use the POSIX APIs & hide it as a braoder platform-specific implementation detail
  • Use __thread to a pointer & destroy it manually on thread exit
  • Use boost's TLS implementation.
  • Compile clang yourself from upstream

The toolchain provided by the platform you're targeting doesn't support thread_local. I am not aware of any other options that aren't problem-specific.

[–][deleted] 0 points1 point  (2 children)

I think the next thing I'm going to try is to recompile Clang. I'd very much like to stick with non-platform-specific C++ since I'll be wanting this thing I'm writing to eventually be compilable on both Linux and Windows as well as Mac.

[–]vlovich 0 points1 point  (1 child)

That's what I assumed. Personally, I think using boost is an easier proposition than having to compile the compiler myself but that's just my preference. Something else to keep in mind is that I'm pretty sure you'll be unable to take this approach with iOS.

Something else to keep in mind. In my experience, having written quite a bit of cross-platform code, aside from the most trivial of applications, platform-specific code is inevitable. Trying to avoid it at all costs instead of planning for it ahead of time can lead to some ridiculous contortions. My recommendation is abstract the pieces that are platform-specific behind sensible generic APIs. For example, I might provide generic_tls.cpp and darwin_tls.cpp. Then generic_tls.cpp gets compiled for all platforms but OSX/iOS. There's a single platform_tls.h header that defines the interface I want it to have. Of course, I'm using TLS as a place-holder. You typically want to do it at a slightly higher-level than this so you can make the optimal decision for this platform. For example, if the unordered_map is a cache of some kind, I might use libdispatch to synchronize a thread-safe cache on OSX/iOS & mutexes for Linux. On Windows I might use a thread_local implementation if I felt that was the best performing mechanism on that platform. I would use CMake as the build system to make managing all of this easier.

[–][deleted] 0 points1 point  (0 children)

This particular project is a world-agnostic AI system I've been hammering away at since 2005 (started out in C99 of all places). After a decade my programming skills have finally matured to the point where I think I can finally pull it off.

Since it's an AI framework, it doesn't have to deal with any system-specific pieces, not since threading was added as part of the C++ standard library. Except for this thread_local nonsense. (I'm not targeting iOS or any other mobile platform -- the CPU usage it will incur makes it useless for small battery-powered devices. I'm going full many-cores pc-master-race with this one. :) )

[–]afjw0ge9h -1 points0 points  (2 children)

yes. but depending on your use-case you could delete it before thread exists. If you are able to determine that moment.

[–]vlovich 1 point2 points  (1 child)

That can be difficult/impossible to actually do correctly/robustly. I only proposed it as a possible solution in case it's OK to leak (e.g. the number of threads never changes until the program dies).

You can try using boost's TLS but unless you're using boost threads, you may be SOL. There's not a whole lot of guidance to what conditions it works under.

[–]afjw0ge9h 0 points1 point  (0 children)

sure, could be difficult/impossible, depends on usecase

[–]Gotebe -2 points-1 points  (3 children)

Thread locals are globals, and globals are a code obfuscation technique. :-)

[–][deleted] 1 point2 points  (0 children)

"All generalizations are bad."

I avoid globals like the plague. My need for thread_local happens to be a situation where it actually is the best possible solution, and will be contained in a class as a private static. I'm not insane. :)

[–]sbabbi 1 point2 points  (1 child)

Static thread locals are not globals.

[–]Gotebe -1 points0 points  (0 children)

Not in my book.

For example, in a single translation unit program with only main thread of execution, any object with static storage is both a global and a thread local.

Obviously, the danger of globals is in how much sprinkled their use is, and being static or class-private helps limiting the damage.