- Why does vector::reserve() not grow exponentially ? - 25 Updates
| Sam <sam@email-scan.com>: Jun 16 08:16AM -0400 Bonita Montero writes: >> Of course they do, it happens all the time. > What I meant was that you can be assured that std::allocator<> > directly or indirectly uses malloc() because what I said. No, you cannot be assured of that. If you don't believe me, see the C++ standard. |
| Sam <sam@email-scan.com>: Jun 16 08:25AM -0400 > Then whats the point of std::atomic? The only time people need atomic > operations is precisely during multithreaded or parallel style programming. > Even SysV semaphores can manage true atomicity between threads. There are some situations where atomic variables are what the doctor ordered. The C++ library's std::shared_ptr is a perfect example. If its destructor decrements the shared reference count and becomes zero it logically means that no other instance of std::shared_ptr exists, so it's safe to destroy the referenced object. In all other cases, the actual non-0 result is irrelevant, and does not have to precisely 54tl4f6 the count of std::shared_ptrs of the same object that remain in scope. But if, at any given moment, all std::shared_ptrs are getting destroyed the atomic counter guarantees that exactly one execution thread's destructor will observe the final reference count of 0, and destroy the object. Who cares which execution thread does it, that's irrelevant. But as long as there is at least one hold-out somewhere it will never reach 0 in any execution thread. Also one could use atomic variables, manually, with memory barriers and reinvent the wheel called "sequencing", if there's some pressing need to do so and std::mutex doesn't fit the bill. |
| David Brown <david.brown@hesbynett.no>: Jun 16 02:43PM +0200 > Hand up. What does it do? Or is it simply the same as static int because > the compiler doesn't care about certain syntax order, the same way that a[0] > and 0[a] are equivalent? "void bar(int a[static 10]);" means "bar" can only be called with a pointer to an array of at least 10 int's. The compiler can optimise the implementation based on that, or warn if the function is called in a way that violates this (for example, with a null pointer). It's a fairly obscure usage, and I think few C programmers will know about it even if they have long experience of the language. I can't say it is a feature I have ever thought to use. You could use: void foo(int a[static 1]); as a portable alternative to gcc's void foo(int * a) __attribute__((nonull)); However, I would say that gcc's syntax is a lot clearer (assuming, of course, you are using a compiler that accepts it). |
| David Brown <david.brown@hesbynett.no>: Jun 16 02:44PM +0200 On 16/06/2021 14:43, David Brown wrote: > void foo(int * a) __attribute__((nonull)); > However, I would say that gcc's syntax is a lot clearer (assuming, of > course, you are using a compiler that accepts it). I forgot to mention - AFAIK, the "void foo(int a[static 1])" syntax does not exist for C++. |
| Juha Nieminen <nospam@thanks.invalid>: Jun 16 01:09PM > presuming that nothing else happens. However, it is unspecified when this > joyous event occurs and is observable by a given execution thread. That > requires sequencing. A variable being atomic guarantees that no thread will see a garbage value for it. In other words, if one thread is changing the value of the atomic variable and another thread is reading it at the same time, that second thread is going to get either the old value or the new value, but it's guaranteed that it will not get some third garbage value. It also guarantees that two threads trying to assign something to the atomic variable will not interfere with each other so that garbage ends up in the variable. The final value will be one or the other (depending on which thread was allowed to access it first and which one after that), and while the variable may contain for a brief moment the value written by the first thread before it gets the value written by the second thread, at no point will it contain any garbage value that's neither (nor the original). Atomic variables (at least with std::atomic) are also what you would call "volatile", in that any read and assignment will happen exactly where the operation appears in the code and nowhere else. The compiler will not optimize it away nor move it somewhere else (such as outside a loop). It will read or assign it precisely where and how many times you say. Of course atomic variables can be misused. They are not locks, fences or semaphores. For example using atomic variable for a spinlock is most probably not going to work unless you use an atomic compare-and-swap instruction or similar. Simply doing a "if(atomic_var == true) { atomic_var = false; dosomething(); }" will not stop two threads from incorrectly entering that critical section at the same time. Atomic variables need to be used correctly. |
| Paavo Helde <myfirstname@osa.pri.ee>: Jun 16 04:10PM +0300 16.06.2021 15:25 Sam kirjutas: > Also one could use atomic variables, manually, with memory barriers and > reinvent the wheel called "sequencing", if there's some pressing need to > do so and std::mutex doesn't fit the bill. As far as I can see the atomics are by default using memory barriers. The default memory ordering is std::memory_order_seq_cst which means memory barriers and lots of other guarantees: https://en.cppreference.com/w/cpp/atomic/memory_order : "Atomic operations tagged memory_order_seq_cst not only order memory the same way as release/acquire ordering (everything that happened-before a store in one thread becomes a visible side effect in the thread that did a load), but also establish a single total modification order of all atomic operations that are so tagged." What you are describing seems more like std::memory_order_relaxed, which is not the default. What I have misunderstood? |
| Juha Nieminen <nospam@thanks.invalid>: Jun 16 01:14PM > "static" in "void bar(int a[static 10]);" is doing?), people will find > unusual ways to express things. And it is best solved by reading each > other's code, talking together, and sharing information. C (and thus usually also C++) can indeed have some weird features that aren't widely known even by experienced programmers. For example, I would bet that quite a large portion of C (and C++) programmers would think this is invalid and doesn't compile: int i = 3; int j = i["hello"]; |
| Juha Nieminen <nospam@thanks.invalid>: Jun 16 01:16PM > You have lost capability to read, Juha, so you build straw-men that I did not > write about C++98 and so then argue with those. Is it even possible to just have a conversation in this newsgroup without accusations being thrown around? Just relax. |
| Bonita Montero <Bonita.Montero@gmail.com>: Jun 16 03:35PM +0200 >> What I meant was that you can be assured that std::allocator<> >> directly or indirectly uses malloc() because what I said. > No, you cannot be assured of that. ... It has nothting to do with the standard. I told you why this is the most reasonable assumption. |
| MrSpook_ucGx3e4l@x8gqtuqjwl9z3g.com: Jun 16 01:47PM On Wed, 16 Jun 2021 08:25:18 -0400 >The C++ library's std::shared_ptr is a perfect example. If its destructor >decrements the shared reference count and becomes zero it logically means >that no other instance of std::shared_ptr exists, so it's safe to destroy Sure, but that only matters in a multi threaded program. And if atomic isn't guaranteed to be thread safe then surely you'd be better off just using mutex locks? |
| MrSpook_g3w@2ur2yrijxtw7d3jt394yu9dp.org: Jun 16 01:48PM On Wed, 16 Jun 2021 14:44:37 +0200 >> course, you are using a compiler that accepts it). >I forgot to mention - AFAIK, the "void foo(int a[static 1])" syntax does >not exist for C++. Is it C99? |
| MrSpook_74D@ov88_wt8h.co.uk: Jun 16 01:54PM On Wed, 16 Jun 2021 14:43:59 +0200 > void foo(int * a) __attribute__((nonull)); >However, I would say that gcc's syntax is a lot clearer (assuming, of >course, you are using a compiler that accepts it). Just tried this with gcc 8.3.0: void func(int a[static 10]) { } int main() { int a[5]; func(a); return 0; } Compiles without errors or warnings even with -Wall -pedantic -Wextra -std=c99 which is obviously not whats intended. Presumably implemented only in the parser, not the core compiler. |
| David Brown <david.brown@hesbynett.no>: Jun 16 03:59PM +0200 > Sure, but that only matters in a multi threaded program. And if atomic > isn't guaranteed to be thread safe then surely you'd be better off just > using mutex locks? The atomics /are/ guaranteed to be thread safe. But they are not guaranteed to be synchronising (depending on the memory order given). The prime point of atomic increments and decrements is that you'll end up with the right number in the result, regardless of the order things are done. This makes relaxed atomics very efficient and lightweight compared to big locks. |
| David Brown <david.brown@hesbynett.no>: Jun 16 04:07PM +0200 >> I forgot to mention - AFAIK, the "void foo(int a[static 1])" syntax does >> not exist for C++. > Is it C99? Yes, I believe so. |
| James Kuyper <jameskuyper@alumni.caltech.edu>: Jun 16 10:38AM -0400 On 6/16/21 7:14 AM, David Brown wrote: ... > programming language doesn't have unusual and rarely used features (and > which language doesn't? Hands up those C experts who know what the > "static" in "void bar(int a[static 10]);" is doing?), Hand up! |
| scott@slp53.sl.home (Scott Lurndal): Jun 16 03:04PM >> a custom allocator/deallocator in the same program that also includes >> C code, too, ... >They don't. As usual, you are wrong. It's quite common in some circles. None of which you've ever had any experience with; nor have you exhibited the programming skills (or interpersonal skills) to survive in those circles. |
| scott@slp53.sl.home (Scott Lurndal): Jun 16 03:09PM >Then whats the point of std::atomic? The only time people need atomic >operations is precisely during multithreaded or parallel style programming. >Even SysV semaphores can manage true atomicity between threads. Incrementing a shared counter without first acquiring a lock is a perfect use for an atomic fetch_and_add (e.g. the ARM64 LDADD instruction or intel LOCK INC). |
| Paavo Helde <myfirstname@osa.pri.ee>: Jun 16 06:10PM +0300 16.06.2021 14:40 Bonita Montero kirjutas: >> executables where our library might be loaded into still use >> whatever they want, typically standard malloc(). > Better replace the global memory-allocation through mimalloc. This would still require access or influence over the main executable, which I (and many other C++ developers) do not have. |
| Bonita Montero <Bonita.Montero@gmail.com>: Jun 16 05:37PM +0200 >>> C code, too, ... >> They don't. > As usual, you are wrong. It's quite common in some circles. ... It's quite stupid to do that. You have to implement an allocator which can be rebound for all types with typename allocator_traits<alloc> ::template rebind_alloc<T> since you can't anticipate what the STL -containers rebind to, i.e. you have to write an allocator whith the full capabilities of malloc(). That's much work and it's almost impossible to beat the performance of common replacement-allocators. So it's just the best way to replace malloc() which is indirectly or directly used by std::allocator<> on all platforms. > None of which you've ever had any experience with; nor have you exhibited > the programming skills (or interpersonal skills) to survive in those circles. I've already built a custom std::allocator<> replacement for special cases where the allocator can be assumed not to be rebound (vector<>). And I would be able to write an efficient allocator like mimalloc; but I wouldn't have invented the basic structures for that - and you not as well. |
| MrSpook_hjesjs@8pot25r5sg1xe.info: Jun 16 03:45PM On Wed, 16 Jun 2021 15:09:58 GMT >Incrementing a shared counter without first acquiring a lock is a perfect >use for an atomic fetch_and_add (e.g. the ARM64 LDADD instruction or intel >LOCK INC). I'm confused. Either std::atomic is thread safe or it isn't. Which is it? |
| Bonita Montero <Bonita.Montero@gmail.com>: Jun 16 05:50PM +0200 > Incrementing a shared counter without first acquiring a lock is a perfect > use for an atomic fetch_and_add (e.g. the ARM64 LDADD instruction or intel > LOCK INC). No, fetch_and_add is LOCK XADD. |
| David Brown <david.brown@hesbynett.no>: Jun 16 07:55PM +0200 > Compiles without errors or warnings even with -Wall -pedantic -Wextra -std=c99 > which is obviously not whats intended. Presumably implemented only in the > parser, not the core compiler. clang warns here, gcc does not. It's a case of clang being a little better and more helpful at the static analysis in this case. The C syntax provides compilers with an opportunity to warn you, but does not require them to do so. You could file this as a bug in gcc if you like (it's a missing feature, rather than a bug, but it goes in the same bugzilla list). |
| David Brown <david.brown@hesbynett.no>: Jun 16 07:58PM +0200 On 16/06/2021 16:38, James Kuyper wrote: >> which language doesn't? Hands up those C experts who know what the >> "static" in "void bar(int a[static 10]);" is doing?), > Hand up! I bet /you/ read the challenge correctly, and are raising your hand because you /do/ know what it means - unlike Mr Spook who raised his hand because he /doesn't/ know. Still, that gave me the excuse to give the answer - which I must have got right, otherwise you'd have corrected me by now :-) |
| "Öö Tiib" <ootiib@hot.ee>: Jun 16 11:03AM -0700 On Wednesday, 16 June 2021 at 16:17:09 UTC+3, Juha Nieminen wrote: > > write about C++98 and so then argue with those. > Is it even possible to just have a conversation in this newsgroup without > accusations being thrown around? Just relax. But I feel relaxed ... my accusations were straight to the point. You in lengths discussed something with what I mostly agree in manner like I had said something that I did not. You avoided discussing what I said that C++17 was horrible, pathetic trash, sabotage of language I liked and so I'm stuck in C++14. |
| Paavo Helde <myfirstname@osa.pri.ee>: Jun 16 09:08PM +0300 >> use for an atomic fetch_and_add (e.g. the ARM64 LDADD instruction or intel >> LOCK INC). > I'm confused. Either std::atomic is thread safe or it isn't. Which is it? Of course it is thread-safe, that's what the name 'atomic' means. Alas, there are many definitions of "thread-safe", so one might easily get confused. In the case of atomics, "thread-safe" at least means the value of a particular atomic is well-defined and predictable when the atomic is accessed from multiple threads. Whether it means anything more depends on the used memory order and other details. |
| 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