- thread local ctor on main... - 6 Updates
- Remove the last argument from a parameter pack - 4 Updates
- Vector with fixed memory size? - 5 Updates
- Available C++ Libraries FAQ - 1 Update
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Dec 14 10:25PM -0800 Fwiw, there is an interesting difference between GCC and MSVC. MSVC automatically calls the thread local constructors. Take this program into account: __________________ #include <iostream> #include <thread> #include <atomic> #include <mutex> #include <cassert> #define THREADS 4 #define CT_MB_ACQ std::memory_order_acquire #define CT_MB_REL std::memory_order_release #define CT_MB_RLX std::memory_order_relaxed static std::atomic<unsigned long> g_per_thread_ctor(0); static std::atomic<unsigned long> g_per_thread_dtor(0); static std::mutex g_cout_mutex; struct ct_per_thread { unsigned long m_id; ct_per_thread() : m_id(g_per_thread_ctor.fetch_add(1, CT_MB_RLX)) { } ~ct_per_thread() { g_per_thread_dtor.fetch_add(1, CT_MB_RLX); } }; static thread_local ct_per_thread g_per_thread; void ct_worker() { ct_per_thread& self = g_per_thread; g_cout_mutex.lock(); std::cout << "ct_worker::(" << self.m_id << ")\n"; g_cout_mutex.unlock(); } int main() { ct_per_thread& self = g_per_thread; std::cout << "main::(" << self.m_id << ")\n"; { std::thread threads[THREADS]; for (unsigned long i = 0; i < THREADS; ++i) { threads[i] = std::thread(ct_worker); } for (unsigned long i = 0; i < THREADS; ++i) { threads[i].join(); } } unsigned long a = g_per_thread_ctor.load(CT_MB_RLX); unsigned long b = g_per_thread_dtor.load(CT_MB_RLX) + 1; std::cout << "a = " << a << "\n"; std::cout << "b = " << b << "\n"; assert(a == b); std::cout << "\n\nmain() - exit\n"; std::cout.flush(); return 0; } __________________ This should product output like, where a is always equal to b: __________________ ct_worker::(1) ct_worker::(2) ct_worker::(3) ct_worker::(4) a = 5 b = 5 __________________ However, on GCC, when one omits the first two lines of code in main: __________________ ct_per_thread& self = g_per_thread; std::cout << "main::(" << self.m_id << ")\n"; __________________ GCC does not call the ctor for self, while MSVC does. Try getting rid of those two lines of code and run it under GCC. It should go something like: __________________ ct_worker::(0) ct_worker::(1) ct_worker::(2) ct_worker::(3) a = 4 b = 5 __________________ Where a does not equal b. Humm... Should the ctor for a thread local be automatically called on thread creation, even main, or... Should it be delayed until a thread actually uses it? Need to dig into the standard. |
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Dec 14 11:01PM -0800 On 12/14/2018 10:25 PM, Chris M. Thomasson wrote: > g_per_thread_dtor.fetch_add(1, CT_MB_RLX); > } > }; [...] Can a thread local be a non-POD type? |
Paavo Helde <myfirstname@osa.pri.ee>: Dec 15 05:06PM +0200 On 15.12.2018 8:25, Chris M. Thomasson wrote: > Should the ctor for a thread local be automatically called on thread > creation, even main, or... Should it be delayed until a thread actually > uses it? Need to dig into the standard. The standard says a thread local "shall be initialized before its first odr-use". I guess this is for supporting the "zero overhead" principle: no resources should be wasted for construction of a thread local in the threads which don't use it. |
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Dec 15 11:48AM -0800 On 12/15/2018 7:06 AM, Paavo Helde wrote: > odr-use". I guess this is for supporting the "zero overhead" principle: > no resources should be wasted for construction of a thread local in the > threads which don't use it. Thanks a million for it really helps clear things up. The funny part is that MSVC still calls the constructor for the thread local in main, even if we delete the lines of code that actually use it. For instance: ________________________ int main() { //ct_per_thread& self = g_per_thread; //std::cout << "main::(" << self.m_id << ")\n"; { std::thread threads[THREADS]; for (unsigned long i = 0; i < THREADS; ++i) { threads[i] = std::thread(ct_worker); } for (unsigned long i = 0; i < THREADS; ++i) { threads[i].join(); } } unsigned long a = g_per_thread_ctor.load(CT_MB_RLX); unsigned long b = g_per_thread_dtor.load(CT_MB_RLX) + 1; std::cout << "a = " << a << "\n"; std::cout << "b = " << b << "\n"; assert(a == b); std::cout << "\n\nmain() - exit\n"; std::cout.flush(); return 0; } ________________________ MSVC outputs: ________________________ ct_worker::(1) ct_worker::(2) ct_worker::(3) ct_worker::(4) a = 5 b = 5 main() - exit ________________________ GCC outputs: ________________________ ct_worker::(1) ct_worker::(2) ct_worker::(0) ct_worker::(3) a = 4 b = 5 Assertion failed! ________________________ GCC is giving the correct output according to the standard. MSVC constructs a ct_per_thread in main no matter what. Humm... |
James Kuyper <jameskuyper@alumni.caltech.edu>: Dec 15 03:37PM -0500 On 12/15/18 02:01, Chris M. Thomasson wrote: ... > Can a thread local be a non-POD type? The only restrictions on the use of thread_local are it "shall be applied only to the names of variables of namespace or block scope and to the names of static data members." (7.1.1p3). Whether or not it's a POD type has no relevance. |
Paavo Helde <myfirstname@osa.pri.ee>: Dec 16 12:05AM +0200 On 15.12.2018 21:48, Chris M. Thomasson wrote: > Thanks a million for it really helps clear things up. The funny part is > that MSVC still calls the constructor for the thread local in main, even > if we delete the lines of code that actually use it. Everything is "before" an event which never happens, so MSVC is arguably correct here from a legal viewpoint. |
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Dec 14 07:22PM -0800 On 12/13/2018 4:13 PM, Chris Vine wrote: > auto callback = [](int a, int b) {std::cout << a + b << std::endl;}; > call_except_last(callback, 5, 6, 7); > } Nice. I can use this for other things. |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 15 11:25AM On Fri, 14 Dec 2018 11:42:27 -0800 (PST) > // here is the problem, I can know that one argument must be omitted, but > // there is no way to remove it with the parameter pack > } I still don't think that I have grasped your problem. If you are writing your own implementation of a signal/slot framework, when invoking the receiving object's member function then, from the arguments supplied by the emitter, only pass it the number of arguments which in fact represents the receiving function's arity. You (the programmer invoking 'connect') must know the arity of the receiving member function that you are "connecting" in your code and which the signal will dispatch. This arity which you must know could be passed in as a function parameter of 'connect', or you could derive it programmatically: see an example below - you would need overloads of the get_arity() function in order to cover const and non-const member functions, but that is a task for you. Since the get_arity() function is constexpr, you could use it together with the tuple and index list approach, but that seems like overkill: instead you could drop the surplus arguments as a runtime operation when invoking the receiving function. Presumably your connect function is a template function so there is lots more work for you to do if you are writing your own generic signal/slot framework. ********************** #include <cstddef> #include <iostream> void my_func2(int a, int b) {} void my_func3(int a, int b, int c) {} template <class Ret, class... Args> constexpr std::size_t get_arity(Ret(*)(Args...)) { return sizeof...(Args); } int main () { std::cout << get_arity(my_func2) << std::endl; std::cout << get_arity(my_func3) << std::endl; } |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 15 12:44PM On Sat, 15 Dec 2018 11:25:47 +0000 > approach, but that seems like overkill: instead you could drop the > surplus arguments as a runtime operation when invoking the receiving > function. By the way, this get_arity() function will not work with lambda expressions. But that is fine - a lambda expression is a function literal supplied by the programmer on the fly. You can document that if passing a lambda expression to your connect() function, then the signature of the lambda expression must match the signal's signature exactly, even if some arguments are unused in the lambda. You can detect lambdas by having a templated catch-all of 'get_arity' for cases where there is no better match, which returns say size_t(-1) to indicate that the arity cannot be deduced. In such a case, you can pass on all the emitter's arguments to the lambda. // where there is no better match template <class Func> constexpr std::size_t get_arity(Func&&) { return (std::size_t) -1; } |
Christian Gollwitzer <auriocus@gmx.de>: Dec 15 10:43PM +0100 Am 14.12.18 um 20:42 schrieb User: > void clicked(int x, bool status, int other); > }; > [...] Have you checked how this was solved by other frameworks? Qt uses a special compiler and runtime string comparison. But there is another library called libsigc++ with a similar functionality based on templates: https://github.com/libsigcplusplus/libsigcplusplus In a previous versions, the number of arguments was limited, because they'd written out the templates for up to 10 arguments. I don't know if that was changed with the advent of variadic templates. Is there a good reason to implement your own framework instead of just using libsigc++? Christian |
Juha Nieminen <nospam@thanks.invalid>: Dec 15 08:25AM > I'd make the C array an array of pointers to objects. If you can have an array of objects instead of an array of pointers to objects, why would you deliberately choose the latter? The former is much easier to use, and usually much more efficient (especially if in the latter case you are allocating each object dynamically and individually). The former is also safer (and easier to use safely) than the latter. The main situation where you would want to use an array of pointers to (dynamically allocated) objects is if those objects are of different types. (In some situations you might also want to do that if what you actually need is an array of "references". Since you can't actually use references in an array, you'll have to use pointers instead.) > avoided. I prefer to think that if you don't understand > how to use them properly, you shouldn't be programming in > a language that supports them. If you can easily and fluently avoid using a pointer, in general it's a good idea to do so. Your code usually becomes simpler, cleaner and safer. This doesn't mean one isn't very experienced in using pointers. |
JiiPee <no@notvalid.com>: Dec 15 10:25AM On 15/12/2018 08:25, Juha Nieminen wrote: >> I'd make the C array an array of pointers to objects. > If you can have an array of objects instead of an array of pointers > to objects, why would you deliberately choose the latter? I used to do the pointer array when I was a beginner because "it looked cool", hehe. But now I prefer objects. Although storing unique pointers is also very safe nowadays, but no reason really to do it other than what you said (polymorphism). > it's a good idea to do so. Your code usually becomes simpler, cleaner > and safer. This doesn't mean one isn't very experienced in using > pointers. yes, I think safety always first even if experienced. It just reduces risk, and reducing risk is good for experienced as well |
scott@slp53.sl.home (Scott Lurndal): Dec 15 03:36PM >> I'd make the C array an array of pointers to objects. >If you can have an array of objects instead of an array of pointers >to objects, why would you deliberately choose the latter? Cache management. |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Dec 15 06:34PM +0100 On 15.12.2018 09:25, Juha Nieminen wrote: >> I'd make the C array an array of pointers to objects. > If you can have an array of objects instead of an array of pointers > to objects, why would you deliberately choose the latter? Generally, not considering the context of the question, the main example is a jagged array. Then there is the array of items of different most derived types. And the case where the pointers /are/ your objects to be stored. But in context, Scott was most probably giving one way of postponing initialization until actual use. Another way to do that is like `std::vector`, with in-place construction in a raw buffer. Cheers!, - Alf |
James Kuyper <jameskuyper@alumni.caltech.edu>: Dec 15 03:31PM -0500 On 12/15/18 03:25, Juha Nieminen wrote: >> I'd make the C array an array of pointers to objects. > If you can have an array of objects instead of an array of pointers > to objects, why would you deliberately choose the latter? Because the objects are much bigger than the pointers, and the array frequently needs to be rearranged. |
Nikki Locke <nikki@trumphurst.com>: Dec 14 11:23PM Available C++ Libraries FAQ URL: http://www.trumphurst.com/cpplibs/ This is a searchable list of libraries and utilities (both free and commercial) available to C++ programmers. If you know of a library which is not in the list, why not fill in the form at http://www.trumphurst.com/cpplibs/cppsub.php Maintainer: Nikki Locke - if you wish to contact me, please use the form on the website. |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment