Wednesday, April 10, 2019

Digest for comp.lang.c++@googlegroups.com - 22 updates in 4 topics

"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 10 10:09PM +0200

Code at bottom.
 
My questions are:
* Why is it crashing with Visual C++?
* Is there a much simpler / efficient / whatever way to do this
(except using C++20 coroutines)?
 
Output with MinGW g++, with logging suppressed:
 
 
Starting.
Thread 3 iteration 0.
Thread 2 iteration 0.
Thread 3 iteration 1.
Thread 2 iteration 1.
Thread 3 iteration 2.
Thread 2 iteration 2.
Thread 3 iteration 3.
Thread 2 iteration 3.
Thread 3 iteration 4.
Thread 2 iteration 4.
Thread 3 iteration 5.
Thread 2 iteration 5.
Thread 3 iteration 6.
Thread 2 iteration 6.
Thread 3 iteration 7.
Thread 2 iteration 7.
Thread 3 iteration 8.
Thread 2 iteration 8.
Thread 3 iteration 9.
Thread 2 iteration 9.
Finished.
 
 
With Visual C++ 2019 there's no ordinary output, and the log output
differs from run to run, but typically
 
 
Starting.
Thread 12828 yielding.
Thread 4076 yielding.
Thread 12828 registering unlocker.
Thread 12828 entering wait state.
Thread 4076 releasing another thread.
 
 
The process exit code is then -1073740791, which Microsoft's errlook
utility tells me is hex 0xC0000409 and that that's an unknown code.
However, mr. Google leads to me to an SO question about it, where an
answer claims that it's STATUS_STACK_BUFFER_OVERRUN, i.e. not an error
code or HRESULT code, but a low level status code.
 
Which means that I can possibly find out by creating a Visual Studio
project and debugging, but debugging threads is tricky, so I ask first.
 
 
-----------------------------------------------------------------------
#include <cppx-core/all.hpp> //
https://github.com/alf-p-steinbach/cppx-core
 
namespace my
{
$use_cppx( is_empty );
using namespace cppx::basic_string_building; // "<<"-notation.
 
$use_std(
clog, endl,
exception,
move,
mutex,
queue,
string,
unique_lock
);
$use_std_namespace_names( this_thread );
 
void log( const string& s )
{
static mutex m;
$with( unique_lock<mutex>( m ) ) { clog << s << endl; }
}
 
class Mutually_exclusive_execution
{
using Lock = unique_lock<mutex>;
 
mutex m_q_access;
queue<Lock*> m_execution_locks_q;
 
static auto popped( queue<Lock*>& q )
-> Lock*
{
Lock* result = q.front();
q.pop();
return result;
}
 
void yield( const bool do_wait )
{
mutex m;
Lock execution_lock( m );
 
log( "Thread "s << this_thread::get_id() << " yielding." );
$with( Lock( m_q_access ) )
{
if( not is_empty( m_execution_locks_q ) )
{
log( "Thread "s << this_thread::get_id() << "
releasing another thread." );
popped( m_execution_locks_q )->unlock(); //
Another thread runs.
log( "Thread "s << this_thread::get_id() << "
release succeeded." );
}
if( do_wait )
{
try
{
log( "Thread "s << this_thread::get_id() << "
registering unlocker." );
m_execution_locks_q.emplace( &execution_lock );
}
catch( const exception& x )
{
log( "!"s << x.what() );
}
}
}
 
if( do_wait )
{
log( "Thread "s << this_thread::get_id() << " entering
wait state." );
//(Lock( m )); // Waits until m is unlocked by
another thread.
$with( Lock( m ) ) {}
}
log( "Thread "s << this_thread::get_id() << " resuming." );
}
 
public:
void yield() { yield( true ); }
void goodbye() { yield( false ); }
};
 
} // namespace my
 
namespace app
{
$use_cppx( up_to );
$use_std( cout, endl, thread );
$use_std_namespace_names( this_thread );
 
void run()
{
my::Mutually_exclusive_execution mee;
const auto f = [&]()
{
for( const int i: up_to( 10 ) )
{
mee.yield();
cout << "Thread " << this_thread::get_id() << "
iteration " << i << "." << endl;
}
mee.goodbye();
};
 
thread t1( f );
thread t2( f );
 
t1.join(); t2.join();
}
} // namespace app
 
#include <stdexcept> // std::exception
#include <stdlib.h> // EXIT_...
$use_std( exception, cerr, cout, endl );
auto main() -> int
{
try
{
cout << "Starting." << endl;
app::run();
cout << "Finished." << endl;
return EXIT_SUCCESS;
}
catch( const exception& x )
{
cerr << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}
-----------------------------------------------------------------------
 
 
Cheers!,
 
- Alf (perplexed, baffled, confounded, bewildered & for the time being
stumped)
"Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com>: Apr 10 01:40PM -0700

On 4/10/2019 1:09 PM, Alf P. Steinbach wrote:
> * Is there a much simpler / efficient / whatever way to do this
>   (except using C++20 coroutines)?
 
> Output with MinGW g++, with logging suppressed:
[...]
> - Alf (perplexed, baffled, confounded, bewildered & for the time being
> stumped)
 
Can you possibly reduce it down to something that does not require all
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...
Paavo Helde <myfirstname@osa.pri.ee>: Apr 10 11:44PM +0300

On 10.04.2019 23:09, Alf P. Steinbach wrote:
> * Why is it crashing with Visual C++?
> * Is there a much simpler / efficient / whatever way to do this
> (except using C++20 coroutines)?
 
If you could translate that to C++ and explain what it is what this is
supposed to do I might be tempted to have a look.
 
As for now my only advice is to not turn too much attention to the
process exit code, its informational value is extremely low. A Windows
exception code from a SEH handler or "Stopped working" box would be
better, in my experience.
"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>

No comments: