- vector<>::erase-behaviour - 7 Updates
- Remove the last argument from a parameter pack - 1 Update
- Undefined Behaviour - 3 Updates
- Mutually exclusive execution for threads, OK with g++ but not MSVC - 7 Updates
- an alternative to finally - 3 Updates
- Nonconst method calls enumerator with const_cast - 1 Update
- Project symbiosis - 1 Update
- Usenet group for compiler development - 2 Updates
| "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 08 02:42PM +0200 On 08.04.2019 14:14, James Kuyper wrote: > argument where the connection is logically valid, but one or more > premises is incorrect, is not fallacious, it's merely wrong, and that's > the case with this argument. Out of context, say as the start of a new thread, it could have been merely wrong, as an argument merely about the standard's wording. It was however posted in the context of discussing interpretations of that wording. With the implication that it was relevant to that discussion. As such it was a fallacy. /And/ wrong. Cheers & hth., - Alf |
| Bonita Montero <Bonita.Montero@gmail.com>: Apr 08 05:06PM +0200 > It seems that if you want an way to specify the n'th element of the > vector, you don't want an iterator, but an numerical index, and use > indexing operations on the vector. No, i want to use iterators. > an extension of a pointer that when working on a sequence always points > to a GIVEN item, and the invalidation rules tells you when that > assumption no longer holds. The invalidation-rules are not necessary here. I gave a nearby implemen- tation of erase and this implementation doesn't invalidate the iterators beginning with the erased element. And guaranteeing that the iterators remain valid doesn't put any restrictions on the implementation. |
| Tim Rentsch <tr.17687@z991.linuxsc.com>: Apr 09 03:45AM -0700 > an extension of a pointer that when working on a sequence always points > to a GIVEN item, and the invalidation rules tells you when that > assumption no longer holds. There is a key idea here, which I don't remember having seen before. Thank you for giving this explanation. |
| Paavo Helde <myfirstname@osa.pri.ee>: Apr 08 08:20PM +0300 On 8.04.2019 18:06, Bonita Montero wrote: > tation of erase and this implementation doesn't invalidate the iterators > beginning with the erased element. And guaranteeing that the iterators > remain valid doesn't put any restrictions on the implementation. So what prohibits you from using your own implementation instead of std::vector::erase()? It looks like nobody else has any problem with the current wording of the standard, so a custom solution for your specific needs seems appropriate. PS. Your implementation lacks a std::move(), without it there would be some unneeded overhead when copying non-trivial types. |
| James Kuyper <jameskuyper@alumni.caltech.edu>: Apr 08 08:14AM -0400 On 4/5/19 10:33 PM, Alf P. Steinbach wrote: >> incorrectly assumed that "gcc folk" didn't exist yet at the relevant >> time. > Yes, his argument totally lacked any logic. Incorrect - the logic of his argument was perfectly valid. The only problem was that one of his premises was incorrect. And it wasn't sufficiently incorrect to completely invalidate the conclusion. If you replace the premise with "gcc was quite young at the time the decision was made", then all you have to do is modify the conclusion slightly - instead of "it's impossible for gcc to have influenced the decision", say instead that "it's improbable that gcc significantly influenced the decision". The weakened conclusion is still strong enough to justify presenting it. >> did) read those words at some later time and form an interpretation of >> them is completely irrelevant to the point he was making. > Right again, it was a fallacious argument, one with no inner logic. In a logical argument, you have premises which are assumed correct, a conclusion that you're trying to prove, and an argument which is supposed to connect those premises to that conclusion. A fallacious argument is one where the logic of that connection is invalid. An argument where the connection is logically valid, but one or more premises is incorrect, is not fallacious, it's merely wrong, and that's the case with this argument. |
| Bonita Montero <Bonita.Montero@gmail.com>: Apr 08 07:32PM +0200 > PS. Your implementation lacks a std::move(), without it there would be > some unneeded overhead when copying non-trivial types. I added a follow-up-posting where I added the move. |
| "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 08 04:09PM +0200 > The only thing that can make an argument fallacious is a violation of > the rules of logic - context can never turn a logically valid argument > into an invalid one. I don't think so, for example because this very response is a counter-example. Cheers!, - Alf |
| Tim Rentsch <tr.17687@z991.linuxsc.com>: Apr 09 03:40AM -0700 >> [...] > Could you please stop replying to my posts. I find your condescension > and overall weirdness unappealing. TIA. The newsgroup is a public forum. I'm sorry if my comments came across as condescending; that doesn't match my mindset while I was writing nor my opinion of you generally. |
| Tim Rentsch <tr.17687@z991.linuxsc.com>: Apr 10 08:52PM -0700 "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> writes: [...] > I'm sorry, I'm getting old, and today had my third kidney stone > trying to take me on. [...] I am truly sorry to hear you are going through this. I will hold off on responses in this thread for at least a few days to give that some time to resolve. I hope you feel better soon. |
| Tim Rentsch <tr.17687@z991.linuxsc.com>: Apr 09 02:23AM -0700 > There is no way to say that the program itself, without considering > its invocation, has UB or no UB. It has the potential for UB. For some > input. My apologies for the long delay in responding. Clearly programs that depend on one or more input values may have undefined behavior for some particular sets of input values. But that doesn't mean all programs may exhibit undefined behavior. Note several points: (A) The program shown depends on an external input; (B) The value of the external input is held in the variable 'n', which is represented in the abstract machine; (C) The circumstance of undefined behavior arises from evaluating the '/' operator; and (D) The division operation has undefined behavior because there is an explicit stipulation of undefined behavior when the denominator has the value zero. Now consider this program: #include <stdio.h> unsigned ss( unsigned, unsigned ); int main(){ printf( " result is %u\n", ss( -1, 0 ) ); return 0; } unsigned ss( unsigned n, unsigned r ){ return n ? ss( n-1, r + n*n ) : r; } There is no external input. Moreover all of the program's constituent elements are well defined: no 'shall' clauses are violated, there are no explicit stipulations of undefined behavior, and there is an explicit definition of behavior for each program construct. In particular the behavior of the function call is defined, with no qualifying statement about memory being available. Do you agree with all that? If not which part(s) do you not agree with? (My comments here are meant to apply to both C and C++, with the same conclusions in the two cases. If you think there are any differences between the two please say what those are and why.) |
| Paavo Helde <myfirstname@osa.pri.ee>: Apr 09 02:06PM +0300 On 9.04.2019 12:23, Tim Rentsch wrote: > ss( unsigned n, unsigned r ){ > return n ? ss( n-1, r + n*n ) : r; > } FWIW, this program appears to compile and run properly in MSVC 2017 Release x64 build, and produces output: result is 2147483648 |
| Sam <sam@email-scan.com>: Apr 10 06:12PM -0400 Alf P. Steinbach writes: > { > mutex m; > Lock execution_lock( m ); A very cursory attempt to understand this: this is a std::unique_lock, that locks this thread's mutex. A pointer to this std::unique_lock gets added to a shared queue. Some other execution thread apparently move-constructs, via the queued pointer to this std::unique_lock, off the queue, and into an automatically-scoped variable, which goes out of scope and gets destroyed. I think that's what's going on here. Not 100% certain, but that seems to be the gist of it. There's some other code that deals with thread synchronization, but I this looks like the key part: Lock moved_lock = move( *popped( m_execution_locks_q ) ); log( "Thread "s << this_thread::get_id() << " moving the lock succeeded." ); moved_lock.unlock(); // Another thread runs. Destructor would do it anyway. log( "Thread "s << this_thread::get_id() << " release succeeded." ); } This seems to be phishing out the pointer from the queue, and std::move-s it into "moved_lock", in a different execution thread. The very first sentence on https://en.cppreference.com/w/cpp/thread/mutex/unlock specifies the following: # The mutex must be locked by the current thread of execution, otherwise, # the behavior is undefined. As far as I can tell, the shown code ends up unlocking a mutex in a different execution thread. As Mr. Spock would say: "highly illogical". |
| Sam <sam@email-scan.com>: Apr 10 07:40PM -0400 Alf P. Steinbach writes: >> different execution thread. As Mr. Spock would say: "highly illogical". > Thanks. I don't understand why the restriction, but given that it's there, > what can I do? Is this where condition variables are needed? Yes. A mutex, a condition variable, and a bool flag can be used to implement a logically-equivalent locking abstraction that can be unlocked by a different execution thread. The bool flag's initial value is false. Your thread-independent locking operation consists of locking the std::mutex, and waiting on the condition variable until the bool flag is false, then setting it to true, then unlocking the mutex. Your unlock operation consists of locking the std::mutex, setting the bool flag to false, notify_all() the condition variable, then unlocking the mutex. Your code is also quite vulnerable to undefined behavior due to the lifetime of its std::mutexes which are instantiated in automatic scope. If the std::mutex goes out of scope and gets destroyed while some other execution thread still attempts to screw around with it, more undefined behavior. I haven't analyzed whether the shown code guarantees that all references to the mutex are gone, before it gets destroyed. But it should not be necessary to rely on this rather fragile dependency. It's far more reliable to use smart pointers to dynamically-allocated objects with your mutex, condition variable, and the bool flag, and have a queue of smart pointers. Whichever thread ends up having the last smart pointer to the object go out of scope will destroy it, without worrying about making sure that it's the right thread. |
| Paavo Helde <myfirstname@osa.pri.ee>: Apr 11 09:50AM +0300 On 11.04.2019 1:28, Alf P. Steinbach wrote: >> As far as I can tell, the shown code ends up unlocking a mutex in a >> different execution thread. As Mr. Spock would say: "highly illogical". > Thanks. I don't understand why the restriction, A mutex is a very simple concept. You lock the mutex for doing some modifications on a shared data state which must appear as a single atomic operation to other threads. If the mutex is locked and unlocked in different threads, then the operation does not look very atomic to me any more. |
| "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 11 12:28AM +0200 On 11.04.2019 00:12, Sam wrote: > # the behavior is undefined. > As far as I can tell, the shown code ends up unlocking a mutex in a > different execution thread. As Mr. Spock would say: "highly illogical". Thanks. I don't understand why the restriction, but given that it's there, what can I do? Is this where condition variables are needed? I'm possibly not quite logical because on painkillers. But. Cheers!, - Alf |
| "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 10 11:08PM +0200 On 10.04.2019 22:40, Chris M. Thomasson wrote: > of the $... stuff? Something that just uses std primitives, perhaps? I > have to learn what those $ things mean "under the covers" in order to > help. Humm... Done. It's just that I prefer coding up things with the macros, cause it's less to write and less to read. Thanks. #if 1 // include <cppx-core/all.hpp> // https://github.com/alf-p-steinbach/cppx-core #include <iostream> #include <stdexcept> #include <thread> #include <mutex> #include <queue> #include <sstream> #include <string>
Subscribe to:
Post Comments (Atom)
|
No comments:
Post a Comment