POSIX-style mutexes and condition variables are actually Mesa-style
monitors.
That's an internal detail. In the POSIX API, you have pthread_cond_wait, which looks like one operation to the caller.
The problem is that you often want multiple condition variables with
one monitor. So this is a nonstarter.
I suggest you make an API where the wait operation has an "int cond_index" parameter to select a condition variable.
The monitor object can be told at construction time how large a vector
of condition variables is required.
Java and .NET have monitor objects instead of a combination of mutexes
and condition variables. The advantage of a monitor object is that when
you wait for a monitor to be signalled you can wait for that and for the mutexe's semaphore to be unlocked in _one_ step. With a condition varia-
ble you have first to wait for the notify()-semaphore to be signalled
and for the mutexe's lock in two steps.
struct monitor
{
monitor();
~monitor();
void lock();
void unlock();
void wait();
void notify();
void notify_all();
Java and .NET have monitor objects instead of a combination of mutexes
and condition variables. The advantage of a monitor object is that when
you wait for a monitor to be signalled you can wait for that and for the mutexe's semaphore to be unlocked in _one_ step. With a condition varia-
ble you have first to wait for the notify()-semaphore to be signalled
and for the mutexe's lock in two steps.
The below code simply has a 32 or 64 bit atomic (depening on if the 64
bit variant is lock-free or not) and the lower half is the number of
threads waiting to enter the mutex part and the upper half is the num-
ber of threads waiting to be notified. As all threads wanting to be
notified are also waiting for the mutex the lower half is always >=
the upper half, which I check for in several asserts.
On Windows waiting to be notified and waiting to lock the mutex part
to be unlocked is done by WaitForMultipleObjects(). On Linux there's
no way to wait for mutliple kernel handles to be signalled, but there
are SystemV semaphore sets which may consist of several semaphores and
you may have multiple operations to proceed atomically on this set.
The drawback of combining the mutex and condition-variable parts is
that you can't have multiple conditions associated with the same mutex.
// monitor.hwhile( ret == -1 && errno == EAGAIN );
#pragma once
#if defined(_WIN32)
#define NOMINMAX
#include <Windows.h>
#elif defined(__unix__)
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/stat.h>
#else
#error unsupported platform
#endif
#include <atomic>
#include <semaphore>
#include <type_traits>
#if defined(_WIN32)
#include "xhandle.h"
#endif
struct monitor
{
monitor();
~monitor();
void lock();
void unlock();
void wait();
void notify();
void notify_all();
private:
inline static thread_local char t_dummy;
static constexpr bool USE64 = std::atomic_int64_t::is_always_lock_free;
using atomic_word_t = std::conditional_t<USE64, uint64_t, uint32_t>;
static constexpr unsigned BITS = USE64 ? 32 : 16;
static constexpr atomic_word_t
ENTER_VALUE = 1,
SIGNAL_VALUE = USE64 ? 1ull << 32 : 1,
ENTER_MASK = USE64 ? (uint32_t)-1 : (uint16_t)-1,
SIGNAL_MASK = USE64 ? (uint64_t)(uint32_t)-1 << 32 : (uint32_t)(uint16_t)-1 << 16;
std::atomic<atomic_word_t> m_atomic;
std::atomic<char *> m_threadId;
std::atomic_uint32_t m_recCount;
#if defined(_WIN32)
static constexpr uint32_t SEM_MAX = std::numeric_limits<LONG>::max();
XHANDLE
m_xhEnterEvt,
m_xhSignalSem;
#elif defined(__unix__)
static constexpr uint32_t SEM_MAX = std::numeric_limits<short>::max();
int m_sems;
int semop( std::initializer_list<sembuf> sems );
#endif
};
// monitor.cpp
#include <iostream>
#include <limits>
#include <system_error>
#include <cassert>
#include "monitor.h"
using namespace std;
monitor::monitor() :
m_atomic( 0 ),
m_threadId( nullptr )
#if defined(_WIN32)
, m_xhEnterEvt( CreateEventA( nullptr, FALSE, FALSE, nullptr ) ),
m_xhSignalSem( CreateSemaphoreA( nullptr, 0, SEM_MAX, nullptr ) ) #elif defined(__unix__)
, m_sems( semget( IPC_PRIVATE, 2, S_IRUSR | S_IWUSR ) )
#endif
{
#if defined(_WIN32)
if( !m_xhEnterEvt.get() || !m_xhSignalSem.get() )
throw system_error( GetLastError(), system_category(), "can't initialize monitor object" );
#elif defined(__unix__)
union semun { int val; void *p; } su;
su.val = 0;
#if defined(__linux__)
if( m_sems == -1 )
#else
if( m_sems == -1 || semctl( m_sems, 0, SETVAL, su ) == -1 ||
semctl( m_sems, 1, SETVAL, su ) == -1 )
#endif
throw system_error( errno, system_category(), "can't initialize
monitor object" );
#endif
}
monitor::~monitor()
{
#if defined(__unix__)
int ret = semctl( m_sems, 0, IPC_RMID );
assert(ret != -1);
#endif
}
void monitor::lock()
{
if( m_threadId.load( memory_order_relaxed ) == &t_dummy )
{
uint32_t oldRecCount = m_recCount.load( memory_order_relaxed );
if( oldRecCount == (uint32_t)-1 )
throw system_error( (int)errc::result_out_of_range, generic_category(), "montor's recursion count saturated" );
m_recCount.store( oldRecCount + 1, memory_order_relaxed );
return;
}
atomic_word_t ref = m_atomic.load( memory_order_relaxed );
do
{
if( (ref & ENTER_MASK) == ENTER_MASK )
throw system_error( (int)errc::result_out_of_range, generic_category(), "montor's locker count saturated" );
assert((ref & ENTER_MASK) >= ref >> BITS);
} while( !m_atomic.compare_exchange_strong( ref, ref + 1, memory_order_acquire, memory_order_relaxed ) );
auto initThread = [&]()
{
m_threadId.store( &t_dummy, memory_order_relaxed );
m_recCount.store( 0, memory_order_relaxed );
};
if( (ref & ENTER_MASK) == ref >> BITS ) [[likely]]
return initThread();
#if defined(_WIN32)
if( WaitForSingleObject( m_xhEnterEvt.get(), INFINITE ) != WAIT_OBJECT_0 )
terminate();
#elif defined(__unix__)
if( semop( { { 0, -1, 0 } } ) )
terminate();
#endif
initThread();
}
void monitor::unlock()
{
if( uint32_t rc; m_threadId.load( memory_order_relaxed ) ==
&t_dummy && (rc = m_recCount.load( memory_order_relaxed )) )
{
m_recCount.store( rc - 1, memory_order_relaxed );
return;
}
atomic_word_t ref = m_atomic.load( memory_order_relaxed );
assert((ref & ENTER_MASK) && m_threadId == &t_dummy);
m_threadId.store( nullptr, memory_order_relaxed );
do
assert((ref & ENTER_MASK) >= ref >> BITS);
while( !m_atomic.compare_exchange_strong( ref, ref - 1, memory_order_release, memory_order_relaxed ) );
if( (ref & ENTER_MASK) == 1 ) [[likely]]
return;
#if defined(_WIN32)
if( !SetEvent( m_xhEnterEvt.get() ) )
terminate();
#elif defined(__unix__)
if( semop( { { 0, 1, IPC_NOWAIT } } ) )
terminate();
#endif
}
void monitor::wait()
{
assert(m_threadId == &t_dummy && !m_recCount);
m_threadId.store( nullptr, memory_order_relaxed );
atomic_word_t ref = m_atomic.load( memory_order_relaxed );
do
assert((ref & ENTER_MASK) > ref >> BITS);
while( !m_atomic.compare_exchange_strong( ref, ref + SIGNAL_VALUE, memory_order_release, memory_order_relaxed ) );
if( (ref & ENTER_MASK) - (ref >> BITS) > 1 )
{
#if defined(_WIN32)
if( !SetEvent( m_xhEnterEvt.get() ) )
terminate();
#elif defined(__unix__)
if( semop( { { 0, 1, IPC_NOWAIT } } ) )
terminate();
#endif
}
#if defined(_WIN32)
HANDLE waitFor[2] { m_xhEnterEvt.get(), m_xhSignalSem.get() };
if( WaitForMultipleObjects( 2, waitFor, TRUE, INFINITE ) != WAIT_OBJECT_0 )
terminate();
#elif defined(__unix__)
if( semop( { { 0, -1, 0 }, { 1, -1, 0 } } ) )
terminate();
#endif
m_threadId.store( &t_dummy, memory_order_relaxed );
m_recCount.store( 0, memory_order_relaxed );
}
void monitor::notify()
{
atomic_word_t ref = m_atomic.load( memory_order_relaxed );
assert((ref & ENTER_MASK) > ref >> BITS && m_threadId == &t_dummy);
uint32_t n;
while( (n = (uint32_t)(ref >> BITS)) && !m_atomic.compare_exchange_strong( ref, ref - SIGNAL_VALUE, memory_order_relaxed, memory_order_relaxed ) );
if( !(ref >> BITS) )
return;
#if defined(_WIN32)
if( !ReleaseSemaphore( m_xhSignalSem.get(), 1, nullptr ) )
terminate();
#elif defined(__unix__)
int ret;
do
ret = semop( { { 1, 1, IPC_NOWAIT } } );
while( ret == EAGAIN );
if( ret )for( ; (ret = semop( { { 1, (short)nRelease, IPC_NOWAIT } } )) == -1 &&
terminate();
#endif
}
void monitor::notify_all()
{
atomic_word_t ref = m_atomic.load( memory_order_relaxed );
assert((ref & ENTER_MASK) > ref >> BITS && m_threadId == &t_dummy);
uint32_t n;
while( (n = (uint32_t)(ref >> BITS)) && !m_atomic.compare_exchange_strong( ref, ref & ENTER_MASK, memory_order_relaxed, memory_order_relaxed ) );
while( n )
{
uint32_t nRelease = n <= SEM_MAX ? n : SEM_MAX;
#if defined(_WIN32)
BOOL succ;
for( ; !(succ = ReleaseSemaphore( m_xhSignalSem.get(), nRelease, nullptr )) && GetLastError() == ERROR_TOO_MANY_POSTS;
nRelease = nRelease > 1 ? nRelease / 2 : nRelease );
if( !succ )
terminate();
#elif defined(__unix__)
int ret;
for( ; (ret = semop( { { 1, (short)nRelease, IPC_NOWAIT } } ))
== EAGAIN;
nRelease = nRelease > 1 ? nRelease / 2 : nRelease );
if( ret )
terminate();
#endif
n -= nRelease;
}
}
#if defined(__unix__)
int monitor::semop( initializer_list<sembuf> sems )
{
int ret;
while( (ret = ::semop( m_sems, const_cast<sembuf *>(sems.begin()), sems.size() )) == EINTR );
return ret;
}
#endif
No, the "monitor" idea you're proposing is different in this
way.
Monitors as they are understood in computer science (first described by
C. A. R. Hoare) do not combine the monitor and condition variables into
one object; they are distinct entities: one monitor, zero to many
conditions.
To avoid muddying the debate with nonstandard terminology, you might
want to call your cockamamie idea "bonitor".
Am 08.11.2023 um 19:16 schrieb Kaz Kylheku:
POSIX-style mutexes and condition variables are actually Mesa-style
monitors.
A monitor is different because the mutex and condition variable
is joined in a monitor which allows the shown optimization while
waiting to be notified.
On 11/8/2023 9:16 AM, Bonita Montero wrote:
Am 08.11.2023 um 15:56 schrieb Bonita Montero:
Java and .NET have monitor objects instead of a combination of mutexes
and condition variables. The advantage of a monitor object is that when
you wait for a monitor to be signalled you can wait for that and for the >>> mutexe's semaphore to be unlocked in _one_ step. With a condition varia- >>> ble you have first to wait for the notify()-semaphore to be signalled
and for the mutexe's lock in two steps.
The below code simply has a 32 or 64 bit atomic (depening on if the 64
bit variant is lock-free or not) and the lower half is the number of
threads waiting to enter the mutex part and the upper half is the num-
ber of threads waiting to be notified. As all threads wanting to be
notified are also waiting for the mutex the lower half is always >=
the upper half, which I check for in several asserts.
On Windows waiting to be notified and waiting to lock the mutex part
to be unlocked is done by WaitForMultipleObjects(). On Linux there's
no way to wait for mutliple kernel handles to be signalled, but there
are SystemV semaphore sets which may consist of several semaphores and
you may have multiple operations to proceed atomically on this set.
The drawback of combining the mutex and condition-variable parts is
that you can't have multiple conditions associated with the same mutex.
[snip code]
Model it through Relacy Race Detector first, if you get any issues, we
can work through them. ;^)
https://github.com/dvyukov/relacy
while( ret == -1 && errno == EAGAIN );
Am 08.11.2023 um 15:56 schrieb Bonita Montero:
Java and .NET have monitor objects instead of a combination of mutexes
and condition variables. The advantage of a monitor object is that when
you wait for a monitor to be signalled you can wait for that and for the
mutexe's semaphore to be unlocked in _one_ step. With a condition varia-
ble you have first to wait for the notify()-semaphore to be signalled
and for the mutexe's lock in two steps.
The below code simply has a 32 or 64 bit atomic (depening on if the 64
bit variant is lock-free or not) and the lower half is the number of
threads waiting to enter the mutex part and the upper half is the num-
ber of threads waiting to be notified. As all threads wanting to be
notified are also waiting for the mutex the lower half is always >=
the upper half, which I check for in several asserts.
On Windows waiting to be notified and waiting to lock the mutex part
to be unlocked is done by WaitForMultipleObjects(). On Linux there's
no way to wait for mutliple kernel handles to be signalled, but there
are SystemV semaphore sets which may consist of several semaphores and
you may have multiple operations to proceed atomically on this set.
The drawback of combining the mutex and condition-variable parts is
that you can't have multiple conditions associated with the same mutex.
On 11/8/2023 11:56 AM, Bonita Montero wrote:
I've implemented a monitor without spurious wakeups.
Yawn.
Am 08.11.2023 um 20:49 schrieb Kaz Kylheku:
No, the "monitor" idea you're proposing is different in this
way.
That's not true. That spurious wakesups may happen with a mutex and
a condition variable are constituted in that both are separate enti-
ties.
I've implemented a monitor without spurious wakeups.
Am 08.11.2023 um 20:49 schrieb Kaz Kylheku:
No, the "monitor" idea you're proposing is different in this
way.
That's not true. That spurious wakesups may happen with a mutex and
a condition variable are constituted in that both are separate enti-
ties. Spuriuos wakesups never happen with my implementation, but
stolen wakeups are still possible.
Monitors as they are understood in computer science (first described by
C. A. R. Hoare) do not combine the monitor and condition variables into
one object; they are distinct entities: one monitor, zero to many
conditions.
The way monitors work does not suggest an implementation, or they can
be based internally on a mutex and a condition variable, but if you
have a monitor that never has spurious wakeups, it is implemented
like mine.
To avoid muddying the debate with nonstandard terminology, you might
want to call your cockamamie idea "bonitor".
I've implemented a monitor without spurious wakeups.
Am 08.11.2023 um 20:49 schrieb Kaz Kylheku:
No, the "monitor" idea you're proposing is different in this
way.
That's not true. That spurious wakesups may happen with a mutex and
a condition variable are constituted in that both are separate enti-
ties. Spuriuos wakesups never happen with my implementation, but
stolen wakeups are still possible.
Monitors as they are understood in computer science (first described by
C. A. R. Hoare) do not combine the monitor and condition variables into
one object; they are distinct entities: one monitor, zero to many
conditions.
The way monitors work does not suggest an implementation, or they can
be based internally on a mutex and a condition variable, but if you
have a monitor that never has spurious wakeups, it is implemented
like mine.
To avoid muddying the debate with nonstandard terminology, you might
want to call your cockamamie idea "bonitor".
I've implemented a monitor without spurious wakeups.
Spurious wakesup are part of the "Mesa semantics" of monitors
and condition variables, in contrast to the "Hoare semantics".
Am 09.11.2023 um 00:25 schrieb Kaz Kylheku:
Spurious wakesup are part of the "Mesa semantics" of monitors
and condition variables, in contrast to the "Hoare semantics".
Hoare monitors suck since they are less efficient.
mutex and condition variables happen to be intimately interconnected.
Look up wait morphing...
Humm... Are you okay Bonita? Anything wrong with you?
On 11/8/2023 1:41 PM, Chris M. Thomasson wrote:
On 11/8/2023 9:16 AM, Bonita Montero wrote:
Am 08.11.2023 um 15:56 schrieb Bonita Montero:
Java and .NET have monitor objects instead of a combination of mutexes >>>> and condition variables. The advantage of a monitor object is that when >>>> you wait for a monitor to be signalled you can wait for that and for
the
mutexe's semaphore to be unlocked in _one_ step. With a condition
varia-
ble you have first to wait for the notify()-semaphore to be signalled
and for the mutexe's lock in two steps.
The below code simply has a 32 or 64 bit atomic (depening on if the 64 >>>> bit variant is lock-free or not) and the lower half is the number of
threads waiting to enter the mutex part and the upper half is the num- >>>> ber of threads waiting to be notified. As all threads wanting to be
notified are also waiting for the mutex the lower half is always >=
the upper half, which I check for in several asserts.
On Windows waiting to be notified and waiting to lock the mutex part
to be unlocked is done by WaitForMultipleObjects(). On Linux there's
no way to wait for mutliple kernel handles to be signalled, but there
are SystemV semaphore sets which may consist of several semaphores and >>>> you may have multiple operations to proceed atomically on this set.
The drawback of combining the mutex and condition-variable parts is
that you can't have multiple conditions associated with the same mutex.
[snip code]
Model it through Relacy Race Detector first, if you get any issues, we
can work through them. ;^)
https://github.com/dvyukov/relacy
There is no shame in using a race detector. If you want me to debug your work, well, its not going to be for free. Believe it or not its not
exactly trivial. You already had to make corrections to your own code.
while( ret == -1 && errno == EAGAIN );
Keep EINTR in mind.
Am 08.11.2023 um 22:49 schrieb Chris M. Thomasson:
Keep EINTR in mind.
EINTR is handled if you inspect my own semop overload function.
Am 08.11.2023 um 22:41 schrieb Chris M. Thomasson:
Model it through Relacy Race Detector first, if you get any issues, we
can work through them. ;^)
https://github.com/dvyukov/relacy
You'd suggest Relacy for a hello world.
Am 09.11.2023 um 05:36 schrieb Chris M. Thomasson:
Humm... Are you okay Bonita? Anything wrong with you?
Hoare monitors relase a waiting thread immediately after a notify()
and that's less efficient.
On 11/8/2023 8:38 PM, Bonita Montero wrote:
Am 09.11.2023 um 05:36 schrieb Chris M. Thomasson:
Humm... Are you okay Bonita? Anything wrong with you?
Hoare monitors relase a waiting thread immediately after a notify()
and that's less efficient.
Yawn.
On 2023-11-08, Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
On 11/8/2023 11:56 AM, Bonita Montero wrote:
I've implemented a monitor without spurious wakeups.
Yawn.
Funnier:
Amine Moulay Ramdane has written seven, likewise dead in the water.
Am 09.11.2023 um 05:42 schrieb Chris M. Thomasson:
On 11/8/2023 8:38 PM, Bonita Montero wrote:
Am 09.11.2023 um 05:36 schrieb Chris M. Thomasson:
Humm... Are you okay Bonita? Anything wrong with you?
Hoare monitors relase a waiting thread immediately after a notify()
and that's less efficient.
Yawn.
Re-acquiring the mutex part of a monitor after notify()
is an superfluous extra part that takes CPU time.
On 11/8/2023 9:08 PM, Bonita Montero wrote:
Am 09.11.2023 um 05:42 schrieb Chris M. Thomasson:
On 11/8/2023 8:38 PM, Bonita Montero wrote:
Am 09.11.2023 um 05:36 schrieb Chris M. Thomasson:
Humm... Are you okay Bonita? Anything wrong with you?
Hoare monitors relase a waiting thread immediately after a notify()
and that's less efficient.
Yawn.
Re-acquiring the mutex part of a monitor after notify()
is an superfluous extra part that takes CPU time.
Look up wait morphing.
On 11/8/2023 9:08 PM, Bonita Montero wrote:
Am 09.11.2023 um 05:42 schrieb Chris M. Thomasson:
On 11/8/2023 8:38 PM, Bonita Montero wrote:
Am 09.11.2023 um 05:36 schrieb Chris M. Thomasson:
Humm... Are you okay Bonita? Anything wrong with you?
Hoare monitors relase a waiting thread immediately after a notify()
and that's less efficient.
Yawn.
Re-acquiring the mutex part of a monitor after notify()
is an superfluous extra part that takes CPU time.
Look up wait morphing.
Am 09.11.2023 um 00:25 schrieb Kaz Kylheku:
Spurious wakesup are part of the "Mesa semantics" of monitors
and condition variables, in contrast to the "Hoare semantics".
Hoare monitors suck since they are less efficient.
Am 09.11.2023 um 00:32 schrieb Chris M. Thomasson:
mutex and condition variables happen to be intimately interconnected.
Look up wait morphing...
With my implementation registering as a thread wanting to enter the
mutex and waiting to be notified is one atomic step. That's only
possible if they're one part.
On 2023-11-09, Bonita Montero <Bonita.Montero@gmail.com> wrote:
Am 09.11.2023 um 00:25 schrieb Kaz Kylheku:
Spurious wakesup are part of the "Mesa semantics" of monitors
and condition variables, in contrast to the "Hoare semantics".
Hoare monitors suck since they are less efficient.
Hoare gave us the concept of monitors and condition variables,
which deserves respect.
The original variant is semantically useful; the guarantees that it
provides can make it easier to reason about correctness.
It's something to know about as part of a well-rounded education
in concurrent programming.
Hoare gave us the concept of monitors and condition variables,
which deserves respect.
On 11/8/2023 9:17 PM, Kaz Kylheku wrote:
On 2023-11-09, Bonita Montero <Bonita.Montero@gmail.com> wrote:
Am 09.11.2023 um 00:25 schrieb Kaz Kylheku:
Spurious wakesup are part of the "Mesa semantics" of monitors
and condition variables, in contrast to the "Hoare semantics".
Hoare monitors suck since they are less efficient.
Hoare gave us the concept of monitors and condition variables,
which deserves respect.
The original variant is semantically useful; the guarantees that it
provides can make it easier to reason about correctness.
It's something to know about as part of a well-rounded education
in concurrent programming.
I concur with that assessment.
Am 09.11.2023 um 06:17 schrieb Kaz Kylheku:
Hoare gave us the concept of monitors and condition variables,
which deserves respect.
Hoare monitors are less efficient since they give up ownership
of the mutex part while notifying. That are two kernel calls
which could be prevented.
Humm... Sounds good. However, I need to try it out. Also, if you don't
mind I might actually model it in relacy.
Am 09.11.2023 um 06:17 schrieb Chris M. Thomasson:
Humm... Sounds good. However, I need to try it out. Also, if you don't
mind I might actually model it in relacy.
I've witten my own unit test. The Win32 code worked immediately,
but the SysV-code didn't work immediately also because I forgot
to have IPC_NOWAIT while releasing a semaphore. Why is there a
way to wait for the release of a mutex to be accepted by another
thread ? Who comes up with that ?
Well, invvvho, it might be prudent of me to model it in Relacy.
The act of me porting your work over into its logic base is
going to get me really intimate with your code.
Keep EINTR in mind.
Model it through Relacy Race Detector first, if you get any issues, we
can work through them. ;^)
https://github.com/dvyukov/relacy
On 11/8/2023 9:22 PM, Bonita Montero wrote:
Am 09.11.2023 um 06:17 schrieb Chris M. Thomasson:
Humm... Sounds good. However, I need to try it out. Also, if you
don't mind I might actually model it in relacy.
I've witten my own unit test. The Win32 code worked immediately,
but the SysV-code didn't work immediately also because I forgot
to have IPC_NOWAIT while releasing a semaphore. Why is there a
way to wait for the release of a mutex to be accepted by another
thread ? Who comes up with that ?
Well, invvvho, it might be prudent of me to model it in Relacy. The act
of me porting your work over into its logic base is going to get me
really intimate with your code.
Am 09.11.2023 um 06:27 schrieb Chris M. Thomasson:
Well, invvvho, it might be prudent of me to model it in Relacy.
The act of me porting your work over into its logic base is
going to get me really intimate with your code.
Just reading the code is easier.
On 11/8/2023 9:27 PM, Chris M. Thomasson wrote:
On 11/8/2023 9:22 PM, Bonita Montero wrote:
Am 09.11.2023 um 06:17 schrieb Chris M. Thomasson:
Humm... Sounds good. However, I need to try it out. Also, if you
don't mind I might actually model it in relacy.
I've witten my own unit test. The Win32 code worked immediately,
but the SysV-code didn't work immediately also because I forgot
to have IPC_NOWAIT while releasing a semaphore. Why is there a
way to wait for the release of a mutex to be accepted by another
thread ? Who comes up with that ?
Well, invvvho, it might be prudent of me to model it in Relacy. The
act of me porting your work over into its logic base is going to get
me really intimate with your code.
Can you feel me? lol. ;^)
I have to work on some of my fractal IFS right now, but, I will try to
port your work over to Relacy. Fwiw, here is a taste of some work I ave
to do right now:
https://paulbourke.net/fractals/multijulia
I am trying to create a nice volumetric form of it.
Yup. Porting your code to Relacy is going to force me to read every damn
line of your code. So, touche?
Am 09.11.2023 um 06:31 schrieb Chris M. Thomasson:
Yup. Porting your code to Relacy is going to force me to read every
damn line of your code. So, touche?
Reading the code doesn't hurt since the functions are short.
Wait morphing is a way that shows how interconnected a mutex actually is
with a condition variable...
Am 09.11.2023 um 06:11 schrieb Chris M. Thomasson:
On 11/8/2023 9:08 PM, Bonita Montero wrote:
Am 09.11.2023 um 05:42 schrieb Chris M. Thomasson:
On 11/8/2023 8:38 PM, Bonita Montero wrote:
Am 09.11.2023 um 05:36 schrieb Chris M. Thomasson:
Humm... Are you okay Bonita? Anything wrong with you?
Hoare monitors relase a waiting thread immediately after a notify()
and that's less efficient.
Yawn.
Re-acquiring the mutex part of a monitor after notify()
is an superfluous extra part that takes CPU time.
Look up wait morphing.
Wait morphing isn't implemented with glibc's condition variables.
My code doen't need that because I'm sleeping on the condvar part
and on the mutex part in *one* step.
Am 09.11.2023 um 06:35 schrieb Chris M. Thomasson:
Wait morphing is a way that shows how interconnected a mutex actually
is with a condition variable...
As you can derive from what I said I know what wait morphing is.
I think wait morphing could be prevented unter systems supporting
SysV seamphores by allocating a semaphore set of two semaphores
for each mutex and leaving the second unused until you have a
condition variable.
Porting your code to Relacy makes me read every damn line.
You masking is interesting.
On 11/8/2023 9:39 PM, Bonita Montero wrote:
Am 09.11.2023 um 06:35 schrieb Chris M. Thomasson:
Wait morphing is a way that shows how interconnected a mutex actually
is with a condition variable...
As you can derive from what I said I know what wait morphing is.
I think wait morphing could be prevented unter systems supporting
SysV seamphores by allocating a semaphore set of two semaphores
for each mutex and leaving the second unused until you have a
condition variable.
Can you move waitsets over from mutex to futex and vise versa?
Am 09.11.2023 um 06:36 schrieb Chris M. Thomasson:
Porting your code to Relacy makes me read every damn line.
You masking is interesting.
My code is understandable if you know MT-primitives
and SysV-IPC. There's nothing "damn" with my code.
Can you move waitsets over from mutex to futex and vise versa?
Am 09.11.2023 um 06:40 schrieb Chris M. Thomasson:
Can you move waitsets over from mutex to futex and vise versa?
glibc doesn't do this either.
On 11/8/2023 9:42 PM, Bonita Montero wrote:
Am 09.11.2023 um 06:40 schrieb Chris M. Thomasson:
Can you move waitsets over from mutex to futex and vise versa?
glibc doesn't do this either.
Wait morphing is not in the realm of the compiler. It's in the kernel.
Wait morphing is not in the realm of the compiler. It's in the kernel.
Am 09.11.2023 um 06:44 schrieb Chris M. Thomasson:
Wait morphing is not in the realm of the compiler. It's in the kernel.
Read this: https://stackoverflow.com/questions/45163701/which-os-platforms-implement-wait-morphing-optimization
Am 09.11.2023 um 06:35 schrieb Chris M. Thomasson:
Wait morphing is a way that shows how interconnected a mutex actually
is with a condition variable...
As you can derive from what I said I know what wait morphing is.
I think wait morphing could be prevented unter systems supporting
SysV seamphores by allocating a semaphore set of two semaphores
for each mutex and leaving the second unused until you have a
condition variable.
On 11/8/2023 9:45 PM, Bonita Montero wrote:
Am 09.11.2023 um 06:44 schrieb Chris M. Thomasson:
Wait morphing is not in the realm of the compiler. It's in the kernel.
Read this:
https://stackoverflow.com/questions/45163701/which-os-platforms-implement-wait-morphing-optimization
Wait morphing can be highly beneficial.
On 11/8/2023 9:45 PM, Bonita Montero wrote:
Am 09.11.2023 um 06:44 schrieb Chris M. Thomasson:
Wait morphing is not in the realm of the compiler. It's in the kernel.
Read this:
https://stackoverflow.com/questions/45163701/which-os-platforms-implement-wait-morphing-optimization
Wait morphing can be highly beneficial.
On 11/8/2023 9:48 PM, Chris M. Thomasson wrote:
On 11/8/2023 9:45 PM, Bonita Montero wrote:
Am 09.11.2023 um 06:44 schrieb Chris M. Thomasson:
Wait morphing is not in the realm of the compiler. It's in the kernel.
Read this:
https://stackoverflow.com/questions/45163701/which-os-platforms-implement-wait-morphing-optimization
Wait morphing can be highly beneficial.
I have to go to work on my fractals right now, will get back to you. I
will mostly have time to port your code into a Relacy unit test sometime later on tonight or tomorrow. This work will be for free for you. Will
you even appreciate it in any way shape or form? Or mock me?
On 11/8/2023 9:40 PM, Bonita Montero wrote:
My code is understandable if you know MT-primitives
and SysV-IPC. There's nothing "damn" with my code.
Oh well, like I said, you seem to be a fun person to work with...
On 11/8/2023 9:50 PM, Chris M. Thomasson wrote:
On 11/8/2023 9:48 PM, Chris M. Thomasson wrote:
On 11/8/2023 9:45 PM, Bonita Montero wrote:
Am 09.11.2023 um 06:44 schrieb Chris M. Thomasson:
Wait morphing is not in the realm of the compiler. It's in the kernel. >>>>Read this:
https://stackoverflow.com/questions/45163701/which-os-platforms-implement-wait-morphing-optimization
Wait morphing can be highly beneficial.
I have to go to work on my fractals right now, will get back to you. I
will mostly have time to port your code into a Relacy unit test
sometime later on tonight or tomorrow. This work will be for free for
you. Will you even appreciate it in any way shape or form? Or mock me?
the funny thing is that I need to model one of my new wait-free queue experiments in Relacy for use in my rendering engine.
Am 09.11.2023 um 06:42 schrieb Chris M. Thomasson:
On 11/8/2023 9:40 PM, Bonita Montero wrote:
My code is understandable if you know MT-primitives
and SysV-IPC. There's nothing "damn" with my code.
Oh well, like I said, you seem to be a fun person to work with...
If you were here we would go through the code together
and you would immediately understand it.
On 11/8/2023 10:32 PM, Bonita Montero wrote:
Am 09.11.2023 um 06:42 schrieb Chris M. Thomasson:
On 11/8/2023 9:40 PM, Bonita Montero wrote:
My code is understandable if you know MT-primitives
and SysV-IPC. There's nothing "damn" with my code.
Oh well, like I said, you seem to be a fun person to work with...
If you were here we would go through the code together
and you would immediately understand it.
Since I have to model one of my experimental algorithms in Relacy
anyway, well, I will be right up in it. Wrt my code, well, its trying to
make some fractals go volumetric and I need to highly efficient and specialized LIFO/FIFO stack/queue system for it. They are running on the
CPU, I might even be able to get it run in shaders, but for now, I need
to work on modeling my sketch of my code in Relacy, create some test
units, and give it a go. Fwiw, here is one of my vector fields:
https://youtu.be/poXeq5V0dso
This used an older queue of mine to help distribute the field processing across multiple processors.
Wait morphing can be highly beneficial.
On 11/8/2023 10:54 PM, Chris M. Thomasson wrote:
On 11/8/2023 10:32 PM, Bonita Montero wrote:
Am 09.11.2023 um 06:42 schrieb Chris M. Thomasson:
On 11/8/2023 9:40 PM, Bonita Montero wrote:
My code is understandable if you know MT-primitives
and SysV-IPC. There's nothing "damn" with my code.
Oh well, like I said, you seem to be a fun person to work with...
If you were here we would go through the code together
and you would immediately understand it.
Since I have to model one of my experimental algorithms in Relacy
anyway, well, I will be right up in it. Wrt my code, well, its trying
to make some fractals go volumetric and I need to highly efficient and
specialized LIFO/FIFO stack/queue system for it. They are running on
the CPU, I might even be able to get it run in shaders, but for now, I
need to work on modeling my sketch of my code in Relacy, create some
test units, and give it a go. Fwiw, here is one of my vector fields:
https://youtu.be/poXeq5V0dso
This used an older queue of mine to help distribute the field
processing across multiple processors.
Fwiw, this one is basically embarrassingly parallel to create each
frame. Well, that is kind of cheating wrt embarrassingly parallel, but,
oh well:
https://youtu.be/DrPp6xfLe4Q
This one is from a recursive algorithm of mine, not too efficient wrt
the generation part that gives me my field points to work with. It takes
a while to render an animation in 4k. The recursive nature of it can
blow a threads stack if I get too detailed. So, I need to refine my
current quick and dirty proof of concept code, so to speak. It is kind
of embarrassingly parallel...
I did a test of my monitor against two mutexes and two condition[...]
variables, playing pingpong with each other. On Windows my imple-
mentation is about 12 times faster than the mentioned mutex with
condvar on a AMD 7950X Zen4 16 core system. Under WSL2 on the
same machine the Linux implementation is 12% faster than my code.
On Linux bare metal with a Zen2 3990X 64 core system my code is
about 8.5% faster.
As I recently found in this that a wait() incurs only one context
switch back and forth I thought my code woudln't be faster, but
on bare metal it actually is faster. And I was really surprised
that the MS condvar implementation is that extremely slow compared
to my monitor.
Am 09.11.2023 um 10:11 schrieb Chris M. Thomasson:
I am just starting to model some of my queue code. Its going to fun to
model your monitor and see if its bites the dust.
The advantage under Linux bare metal is only 12%, if you do additional
things in userspace the effect should become smaller. So measuring a
simple bool ping pong shows almost the sole performance of my code.
But you would get a noticeable difference with Windows.
I am just starting to model some of my queue code. Its going to fun to
model your monitor and see if its bites the dust.
On 11/9/2023 1:17 AM, Bonita Montero wrote:
Am 09.11.2023 um 10:11 schrieb Chris M. Thomasson:
I am just starting to model some of my queue code. Its going to fun
to model your monitor and see if its bites the dust.
The advantage under Linux bare metal is only 12%, if you do additional
things in userspace the effect should become smaller. So measuring a
simple bool ping pong shows almost the sole performance of my code.
But you would get a noticeable difference with Windows.
Modeling it is not about sheer performance, it is about correctness.
frame #13: 0x00000001000063d4 cond_var`std::__1::vector<std::__1::thread, std::__1::allocator<std::__1::thread>>::resize(this=0x000000016fdff030 size=2, __sz=0) at vector:1912:15
frame #14: 0x0000000100005eec cond_var`main(argc=1, argv=0x000000016fdff420) at test_cond.cpp:52:10
frame #15: 0x000000018bff50e0 dyld`start + 2360
I did a test of my monitor against two mutexes and two condition
variables, playing pingpong with each other. On Windows my imple-
mentation is about 12 times faster than the mentioned mutex with
condvar on a AMD 7950X Zen4 16 core system. Under WSL2 on the
same machine the Linux implementation is 12% faster than my code.
On Linux bare metal with a Zen2 3990X 64 core system my code is
about 8.5% faster.
As I recently found in this that a wait() incurs only one context
switch back and forth I thought my code woudln't be faster, but
on bare metal it actually is faster. And I was really surprised
that the MS condvar implementation is that extremely slow compared
to my monitor.
Am 10.11.2023 um 14:56 schrieb Branimir Maksimovic:
frame #13: 0x00000001000063d4
cond_var`std::__1::vector<std::__1::thread,
std::__1::allocator<std::__1::thread>>::resize(this=0x000000016fdff030
size=2, __sz=0) at vector:1912:15
frame #14: 0x0000000100005eec cond_var`main(argc=1,
argv=0x000000016fdff420) at test_cond.cpp:52:10
frame #15: 0x000000018bff50e0 dyld`start + 2360
It seems that resizing the thread-vector while doing an emplace_back(),
which itself seems to be inlined, fails. I don't know why.
Am 10.11.2023 um 14:56 schrieb Branimir Maksimovic:
frame #13: 0x00000001000063d4
cond_var`std::__1::vector<std::__1::thread,
std::__1::allocator<std::__1::thread>>::resize(this=0x000000016fdff030
size=2, __sz=0) at vector:1912:15
frame #14: 0x0000000100005eec cond_var`main(argc=1,
argv=0x000000016fdff420) at test_cond.cpp:52:10
frame #15: 0x000000018bff50e0 dyld`start + 2360
It seems that resizing the thread-vector while doing an emplace_back(),
which itself seems to be inlined, fails. I don't know why.
Am 10.11.2023 um 15:08 schrieb Bonita Montero:
Am 10.11.2023 um 14:56 schrieb Branimir Maksimovic:
frame #13: 0x00000001000063d4
cond_var`std::__1::vector<std::__1::thread,
std::__1::allocator<std::__1::thread>>::resize(this=0x000000016fdff030
size=2, __sz=0) at vector:1912:15
frame #14: 0x0000000100005eec cond_var`main(argc=1,
argv=0x000000016fdff420) at test_cond.cpp:52:10
frame #15: 0x000000018bff50e0 dyld`start + 2360
It seems that resizing the thread-vector while doing an emplace_back(),
which itself seems to be inlined, fails. I don't know why.
I think I've got it: I'm using C++20 jthreads which are joined on the destruction of the jthread object. I'm just resizing the jthread vector
to join both threads. But your jthread-implementation seems to behave
like a normal C++11 thread which calls abort() on destruction when a
thread which is joinable and not joind.
You may verify that with this code.
#include <thread>
using namespace std;
int main()
{
(void)jthread( []() { this_thread::sleep_for( 1s ); } );
}
The temporary is very like to be destructed before the thread
is terminated.
Am 10.11.2023 um 21:44 schrieb Chris M. Thomasson:
On 11/10/2023 6:08 AM, Bonita Montero wrote:
Am 10.11.2023 um 14:56 schrieb Branimir Maksimovic:
frame #13: 0x00000001000063d4
cond_var`std::__1::vector<std::__1::thread,
std::__1::allocator<std::__1::thread>>::resize(this=0x000000016fdff030 size=2, __sz=0) at vector:1912:15
frame #14: 0x0000000100005eec cond_var`main(argc=1,
argv=0x000000016fdff420) at test_cond.cpp:52:10
frame #15: 0x000000018bff50e0 dyld`start + 2360
It seems that resizing the thread-vector while doing an emplace_back(),
which itself seems to be inlined, fails. I don't know why.
You should of modeled in a race-detector first!
To find bugs inside his jthread-implementation ?
On 11/10/2023 6:08 AM, Bonita Montero wrote:
Am 10.11.2023 um 14:56 schrieb Branimir Maksimovic:
frame #13: 0x00000001000063d4
cond_var`std::__1::vector<std::__1::thread,
std::__1::allocator<std::__1::thread>>::resize(this=0x000000016fdff030 size=2, __sz=0) at vector:1912:15
frame #14: 0x0000000100005eec cond_var`main(argc=1,
argv=0x000000016fdff420) at test_cond.cpp:52:10
frame #15: 0x000000018bff50e0 dyld`start + 2360
It seems that resizing the thread-vector while doing an emplace_back(),
which itself seems to be inlined, fails. I don't know why.
You should of modeled in a race-detector first!
Am 10.11.2023 um 21:44 schrieb Chris M. Thomasson:
On 11/10/2023 6:08 AM, Bonita Montero wrote:
Am 10.11.2023 um 14:56 schrieb Branimir Maksimovic:
frame #13: 0x00000001000063d4
cond_var`std::__1::vector<std::__1::thread,
std::__1::allocator<std::__1::thread>>::resize(this=0x000000016fdff030 size=2, __sz=0) at vector:1912:15
frame #14: 0x0000000100005eec cond_var`main(argc=1,
argv=0x000000016fdff420) at test_cond.cpp:52:10
frame #15: 0x000000018bff50e0 dyld`start + 2360
It seems that resizing the thread-vector while doing an emplace_back(),
which itself seems to be inlined, fails. I don't know why.
You should of modeled in a race-detector first!
To find bugs inside his jthread-implementation ?
Lola@MacBook-Air News % ./cond_var
3566.26
3292.95
if( m_sems == -1 || zeroSem() )if( m_sems == -1 || !zeroSem() )
Am 11.11.2023 um 11:41 schrieb Bonita Montero:
if( m_sems == -1 || zeroSem() )if( m_sems == -1 || !zeroSem() )
I think I've put the finishing touches to the code now. For the mutex[...]
part I introduced spinning, which I adopted from glibc. Spinning usually
On 11/11/2023 7:39 AM, Bonita Montero wrote:Chris, I think you are preaching to the deaf. I would give up 5 times
Am 11.11.2023 um 11:41 schrieb Bonita Montero:
if( m_sems == -1 || zeroSem() )if( m_sems == -1 || !zeroSem() )
Is that yet another bug correction? Remember my advise, get it working
then try to make it faster.
Am 09.11.2023 um 05:42 schrieb Chris M. Thomasson:is exactly what Java does -- and it does it for reason.
On 11/8/2023 8:38 PM, Bonita Montero wrote:
Am 09.11.2023 um 05:36 schrieb Chris M. Thomasson:
Humm... Are you okay Bonita? Anything wrong with you?
Hoare monitors relase a waiting thread immediately after a notify()
and that's less efficient.
Yawn.
Re-acquiring the mutex part of a monitor after notify()
is an superfluous extra part that takes CPU time.
Is that yet another bug correction? Remember my advise, get it working
then try to make it faster.
Bonita Montero wrote:
Am 09.11.2023 um 05:42 schrieb Chris M. Thomasson:is exactly what Java does -- and it does it for reason.
On 11/8/2023 8:38 PM, Bonita Montero wrote:
Am 09.11.2023 um 05:36 schrieb Chris M. Thomasson:
Humm... Are you okay Bonita? Anything wrong with you?
Hoare monitors relase a waiting thread immediately after a notify()
and that's less efficient.
Yawn.
Re-acquiring the mutex part of a monitor after notify()
is an superfluous extra part that takes CPU time.
No, Java and .net keep holding the mutex while doing a notify().
That's called a Mesa monitor.
I don't suspect that is part of Mesa semantics. (It's definitely part of Hoare semantics.) Do you have a reference?
Since under Mesa semantics, threads re-acquire the mutex with fewer guarantees and must re-test the desired condition, Mesa semantics
supports the more efficient protocol of signaling outside of the
monitor.
If you're using POSIX mutexes and conditions, you should call pthread_cond_signal and pthread_cond_broadcast outside of the
mutex, whenever possible.
Am 12.11.2023 um 06:02 schrieb Kaz Kylheku:
I don't suspect that is part of Mesa semantics. (It's definitely part of
Hoare semantics.) Do you have a reference?
Wikipedia (https://en.wikipedia.org/wiki/Monitor_(synchronization):
"With nonblocking condition variables (also called "Mesa style"
condition variables or "signal and continue" condition variables),
signaling does not cause the signaling thread to lose occupancy
of the monitor. Instead the signaled threads are moved to the e
queue."
Since under Mesa semantics, threads re-acquire the mutex with fewer
guarantees and must re-test the desired condition, Mesa semantics
supports the more efficient protocol of signaling outside of the
monitor.
This is a theoretical advantage. In fact, a combination of mutex
and condition variable, like a monitor implicitly is, is intended
for procuder-consumer patterns. And at this point it never happens
that you want to signal something but don't modify a common state.
If you're using POSIX mutexes and conditions, you should call
pthread_cond_signal and pthread_cond_broadcast outside of the
mutex, whenever possible.
That actually never happens because you have to lock the mutex
anyway.
Am 12.11.2023 um 06:02 schrieb Kaz Kylheku:
I don't suspect that is part of Mesa semantics. (It's definitely part of
Hoare semantics.) Do you have a reference?
Wikipedia (https://en.wikipedia.org/wiki/Monitor_(synchronization):
"With nonblocking condition variables (also called "Mesa style"
condition variables or "signal and continue" condition variables),
signaling does not cause the signaling thread to lose occupancy
of the monitor. Instead the signaled threads are moved to the e
queue."
Since under Mesa semantics, threads re-acquire the mutex with fewer
guarantees and must re-test the desired condition, Mesa semantics
supports the more efficient protocol of signaling outside of the
monitor.
This is a theoretical advantage.
If you're using POSIX mutexes and conditions, you should call
pthread_cond_signal and pthread_cond_broadcast outside of the
mutex, whenever possible.
That actually never happens because you have to lock the mutex
anyway.
Am 11.11.2023 um 20:42 schrieb Chris M. Thomasson:
Is that yet another bug correction? Remember my advise, get it working
then try to make it faster.
The code immediately crashed because of an exception;
easiest debugging.
Am 12.11.2023 um 06:02 schrieb Kaz Kylheku:
I don't suspect that is part of Mesa semantics. (It's definitely part of
Hoare semantics.) Do you have a reference?
Wikipedia (https://en.wikipedia.org/wiki/Monitor_(synchronization):
"With nonblocking condition variables (also called "Mesa style"
condition variables or "signal and continue" condition variables),
signaling does not cause the signaling thread to lose occupancy
of the monitor. Instead the signaled threads are moved to the e
queue."
Since under Mesa semantics, threads re-acquire the mutex with fewer
guarantees and must re-test the desired condition, Mesa semantics
supports the more efficient protocol of signaling outside of the
monitor.
This is a theoretical advantage. In fact, a combination of mutex
and condition variable, like a monitor implicitly is, is intended
for procuder-consumer patterns. And at this point it never happens
that you want to signal something but don't modify a common state.
If you're using POSIX mutexes and conditions, you should call
pthread_cond_signal and pthread_cond_broadcast outside of the
mutex, whenever possible.
That actually never happens because you have to lock the mutex
anyway.
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 12.11.2023 um 06:02 schrieb Kaz Kylheku:
I don't suspect that is part of Mesa semantics. (It's definitely part of >>> Hoare semantics.) Do you have a reference?
Wikipedia (https://en.wikipedia.org/wiki/Monitor_(synchronization):
"With nonblocking condition variables (also called "Mesa style"
condition variables or "signal and continue" condition variables),
signaling does not cause the signaling thread to lose occupancy
of the monitor. Instead the signaled threads are moved to the e
queue."
Since under Mesa semantics, threads re-acquire the mutex with fewer
guarantees and must re-test the desired condition, Mesa semantics
supports the more efficient protocol of signaling outside of the
monitor.
This is a theoretical advantage. In fact, a combination of mutex
and condition variable, like a monitor implicitly is, is intended
for procuder-consumer patterns. And at this point it never happens
that you want to signal something but don't modify a common state.
If you're using POSIX mutexes and conditions, you should call
pthread_cond_signal and pthread_cond_broadcast outside of the
mutex, whenever possible.
That actually never happens because you have to lock the mutex
anyway.
No, you don't. If you updated the predicate that the condition
variable is monitoring while holding the mutex, you should release
the mutex before signaling or broadcasting the condition variable
to avoid unnecessary context switches.
Am 11.11.2023 um 23:45 schrieb Pavel:
Bonita Montero wrote:
Am 09.11.2023 um 05:42 schrieb Chris M. Thomasson:is exactly what Java does -- and it does it for reason.
On 11/8/2023 8:38 PM, Bonita Montero wrote:
Am 09.11.2023 um 05:36 schrieb Chris M. Thomasson:
Humm... Are you okay Bonita? Anything wrong with you?
Hoare monitors relase a waiting thread immediately after a notify()
and that's less efficient.
Yawn.
Re-acquiring the mutex part of a monitor after notify()
No, Java and .net keep holding the mutex while doing a notify().
That's called a Mesa monitor.
is an superfluous extra part that takes CPU time.
On 2023-11-12, Bonita Montero <Bonita.Montero@gmail.com> wrote:She doesn't. See my citation in response to her post for the reference
No, Java and .net keep holding the mutex while doing a notify().
That's called a Mesa monitor.
I don't suspect that is part of Mesa semantics. (It's definitely part of Hoare semantics.) Do you have a reference?
Since under Mesa semantics, threads re-acquire the mutex with fewer guarantees and must re-test the desired condition, Mesa semanticsThis is recommended against by the standard for the same reason why Java implements Hoare monitor behavior. Citation:
supports the more efficient protocol of signaling outside of the
monitor.
If you're using POSIX mutexes and conditions, you should call pthread_cond_signal and pthread_cond_broadcast outside of the mutex,
whenever possible.
(In a nutshell, if you're going to be telling some thread(s) to go ahead
and grab a mutex, get the hell out of their way first).
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 12.11.2023 um 06:02 schrieb Kaz Kylheku:
I don't suspect that is part of Mesa semantics. (It's definitely part of >>> Hoare semantics.) Do you have a reference?
Wikipedia (https://en.wikipedia.org/wiki/Monitor_(synchronization):
"With nonblocking condition variables (also called "Mesa style"
condition variables or "signal and continue" condition variables),
signaling does not cause the signaling thread to lose occupancy
of the monitor. Instead the signaled threads are moved to the e
queue."
Since under Mesa semantics, threads re-acquire the mutex with fewer
guarantees and must re-test the desired condition, Mesa semantics
supports the more efficient protocol of signaling outside of the
monitor.
This is a theoretical advantage. In fact, a combination of mutex
and condition variable, like a monitor implicitly is, is intended
for procuder-consumer patterns. And at this point it never happens
that you want to signal something but don't modify a common state.
If you're using POSIX mutexes and conditions, you should call
pthread_cond_signal and pthread_cond_broadcast outside of the
mutex, whenever possible.
That actually never happens because you have to lock the mutex
anyway.
No, you don't. If you updated the predicate that the condition
variable is monitoring while holding the mutex, you should release
the mutex before signaling or broadcasting the condition variable
to avoid unnecessary context switches.
Kaz Kylheku wrote:
On 2023-11-12, Bonita Montero <Bonita.Montero@gmail.com> wrote:She doesn't. See my citation in response to her post for the reference
No, Java and .net keep holding the mutex while doing a notify().
That's called a Mesa monitor.
I don't suspect that is part of Mesa semantics. (It's definitely part of
Hoare semantics.) Do you have a reference?
to the contrary.
This is recommended against by the standard for the same reason why Java implements Hoare monitor behavior. Citation:
Since under Mesa semantics, threads re-acquire the mutex with fewer
guarantees and must re-test the desired condition, Mesa semantics
supports the more efficient protocol of signaling outside of the
monitor.
If you're using POSIX mutexes and conditions, you should call
pthread_cond_signal and pthread_cond_broadcast outside of the mutex,
whenever possible.
"
The pthread_cond_broadcast() or pthread_cond_signal() functions may be
called by a thread whether or not it currently owns the mutex that
threads calling pthread_cond_wait() or pthread_cond_timedwait() have associated with the condition variable during their waits; however, if predictable scheduling behavior is required, then that mutex shall be locked by the thread calling pthread_cond_broadcast() or pthread_cond_signal(). > "
(In a nutshell, if you're going to be telling some thread(s) to go ahead
and grab a mutex, get the hell out of their way first).
Scott Lurndal wrote:
No, you don't. If you updated the predicate that the conditionWhy would you have additional context switches if you signal before
variable is monitoring while holding the mutex, you should release
the mutex before signaling or broadcasting the condition variable
to avoid unnecessary context switches.
releasing the lock?
Kaz Kylheku wrote:
If you're using POSIX mutexes and conditions, you should callThis is recommended against by the standard for the same reason why Java implements Hoare monitor behavior. Citation:
pthread_cond_signal and pthread_cond_broadcast outside of the mutex,
whenever possible.
"
The pthread_cond_broadcast() or pthread_cond_signal() functions may be
called by a thread whether or not it currently owns the mutex that threads calling pthread_cond_wait() or pthread_cond_timedwait() have associated with the condition variable during their waits; however, if predictable scheduling behavior is required, then that mutex shall be locked by the thread calling pthread_cond_broadcast() or pthread_cond_signal().
"
No, you don't. If you updated the predicate that the condition
variable is monitoring while holding the mutex, you should release
the mutex before signaling or broadcasting the condition variable
to avoid unnecessary context switches.
This is a theoretical advantage.
No it isn't. ...
Am 12.11.2023 um 18:53 schrieb Scott Lurndal:
No, you don't. If you updated the predicate that the condition
variable is monitoring while holding the mutex, you should release
the mutex before signaling or broadcasting the condition variable
to avoid unnecessary context switches.
The context switch occurs only if _both_ conditions are met:
the mutex is unlocked and the condition variable is signalled.
Ah, your not an expert on operating systems, it seems.
Sorry, the code worked, but I don't need an atomic:[...]
It's early in the morning ...
On 2023-11-13, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote:
Kaz Kylheku wrote:
If you're using POSIX mutexes and conditions, you should callThis is recommended against by the standard for the same reason why Java
pthread_cond_signal and pthread_cond_broadcast outside of the mutex,
whenever possible.
implements Hoare monitor behavior. Citation:
"
The pthread_cond_broadcast() or pthread_cond_signal() functions may be
called by a thread whether or not it currently owns the mutex that
threads calling pthread_cond_wait() or pthread_cond_timedwait() have
associated with the condition variable during their waits; however, if
predictable scheduling behavior is required, then that mutex shall be
locked by the thread calling pthread_cond_broadcast() or
pthread_cond_signal().
"
But that text is stupid/defective, because you will not actually get predictable scheduling behavior just by doing that.
Signal the condition while still holding the mutex doesn't give you any guarantees about which thread will get the mutex next.
Suppose:
1. The signal operation wake up the next waiting thread.
2. The signaler then gives up the mutex.
3. Before that awoken next-waiting-thread gets the mutex, some
another thread comes along and seizes the mutex.
Signaling in the mutex can blow up the critical region from "handful of instructions" to "hundreds of instructions".
If we compare:
mutex_lock(&stack->lock);
node->next = stack->top;
stack->top = node;
mutex_unlock(&stack->lock);
cond_signal(&stack->item_pushed);
All that is in the critical region are the mutex are the list
manipulation instructions, plus some of the mutex code itself.
If we move cond_signal before mutex_unlock, everything done by that
function, including potentially going into the kernel to wake up a
thread, is now in the mutex.
That's a lot to pay for some vague, unfulfillable promise of
"predictable scheduling behavior", on which you can base approximately nothing.
Hoare semantics gives you something: that if there are waiting tasks
queued on a condition, the monitor is transferred to the first waiting
one. *And* (I seem to recall) when that thread leaves the monitor, the original signaler gets it again!
On 2023-11-13, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote:
Kaz Kylheku wrote:
If you're using POSIX mutexes and conditions, you should callThis is recommended against by the standard for the same reason why Java
pthread_cond_signal and pthread_cond_broadcast outside of the mutex,
whenever possible.
implements Hoare monitor behavior. Citation:
"
The pthread_cond_broadcast() or pthread_cond_signal() functions may be
called by a thread whether or not it currently owns the mutex that
threads calling pthread_cond_wait() or pthread_cond_timedwait() have
associated with the condition variable during their waits; however, if
predictable scheduling behavior is required, then that mutex shall be
locked by the thread calling pthread_cond_broadcast() or
pthread_cond_signal().
"
But that text is stupid/defective, because you will not actually get predictable scheduling behavior just by doing that.
On 2023-11-13, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote:
Scott Lurndal wrote:
No, you don't. If you updated the predicate that the conditionWhy would you have additional context switches if you signal before
variable is monitoring while holding the mutex, you should release
the mutex before signaling or broadcasting the condition variable
to avoid unnecessary context switches.
releasing the lock?
Because of the situation that the thread which was signaled is
trying to acquire the mutex, which, stupidly, the signaling thread
is still holding. So, oops, back it goes into suspended state, and we
have to context switch to the mutex holder which has to release the
mutex and then switch to that signaled thread again.
On 2023-11-13, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote:This is a gray area, the specs says:
Kaz Kylheku wrote:
If you're using POSIX mutexes and conditions, you should callThis is recommended against by the standard for the same reason why Java
pthread_cond_signal and pthread_cond_broadcast outside of the mutex,
whenever possible.
implements Hoare monitor behavior. Citation:
"
The pthread_cond_broadcast() or pthread_cond_signal() functions may be
called by a thread whether or not it currently owns the mutex that
threads calling pthread_cond_wait() or pthread_cond_timedwait() have
associated with the condition variable during their waits; however, if
predictable scheduling behavior is required, then that mutex shall be
locked by the thread calling pthread_cond_broadcast() or
pthread_cond_signal().
"
But that text is stupid/defective, because you will not actually get predictable scheduling behavior just by doing that.
Signal the condition while still holding the mutex doesn't give you any guarantees about which thread will get the mutex next.
Suppose:
1. The signal operation wake up the next waiting thread.
2. The signaler then gives up the mutex.
3. Before that awoken next-waiting-thread gets the mutex, some
another thread comes along and seizes the mutex.
Signaling in the mutex can blow up the critical region from "handful of instructions" to "hundreds of instructions".RT is all about discipline to achieve low latency of serving some
If we compare:
mutex_lock(&stack->lock);
node->next = stack->top;
stack->top = node;
mutex_unlock(&stack->lock);
cond_signal(&stack->item_pushed);
All that is in the critical region are the mutex are the list
manipulation instructions, plus some of the mutex code itself.
If we move cond_signal before mutex_unlock, everything done by that
function, including potentially going into the kernel to wake up a
thread, is now in the mutex.
That's a lot to pay for some vague, unfulfillable promise of
"predictable scheduling behavior", on which you can base approximately nothing.
Hoare semantics gives you something: that if there are waiting tasks
queued on a condition, the monitor is transferred to the first waiting
one. *And* (I seem to recall) when that thread leaves the monitor, the original signaler gets it again!
Kaz Kylheku wrote:
Because of the situation that the thread which was signaled isPlease see my response to your other post. "as-if" calling of pthread_mutex_lock does not prescribe actually calling it. Nothing in
trying to acquire the mutex, which, stupidly, the signaling thread
is still holding. So, oops, back it goes into suspended state, and we
have to context switch to the mutex holder which has to release the
mutex and then switch to that signaled thread again.
the standard prevents pthread_cond_signal from doing all the job of
stuffing the unblocked threads to the mutex waiting list in accordance
with some scheduling policy.
"as-if" and "according to the scheduling policy (if applicable)" here
are important. The standard intent may be to permit only the threads
that are "unblocked" contend for the mutex -- as opposed to all
non-blocked threads.
On 11/12/2023 10:47 PM, Bonita Montero wrote:
Sorry, the code worked, but I don't need an atomic:[...]
It's early in the morning ...
Yawn. Why not make sure it works _first_!?
Am 13.11.2023 um 21:50 schrieb Chris M. Thomasson:
On 11/12/2023 10:47 PM, Bonita Montero wrote:
Sorry, the code worked, but I don't need an atomic:[...]
It's early in the morning ...
Yawn. Why not make sure it works _first_!?
The first code worked but the atomic could be a normal uint64_t
since its access is surrounded by a mutex lock and unlock.
On 2023-11-14, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote:
"as-if" and "according to the scheduling policy (if applicable)" here
are important. The standard intent may be to permit only the threads
that are "unblocked" contend for the mutex -- as opposed to all
non-blocked threads.
It's possible that only one thread is unblocked by a
pthread_cond_signal. It takes at least two parties to contend for
something.
On 11/13/2023 7:27 PM, Kaz Kylheku wrote:
On 2023-11-14, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo>
wrote:
"as-if" and "according to the scheduling policy (if applicable)" here
are important. The standard intent may be to permit only the threads
that are "unblocked" contend for the mutex -- as opposed to all
non-blocked threads.
It's possible that only one thread is unblocked by a
pthread_cond_signal. It takes at least two parties to contend for
something.
A signalling thread does its thing while holding the mutex... Well, it
hears the following playing in the background:
https://youtu.be/7YvAYIJSSZY
You mean a word wrt the arch, or uint64_t on a 32-bit system?
Am 14.11.2023 um 06:21 schrieb Chris M. Thomasson:
You mean a word wrt the arch, or uint64_t on a 32-bit system?
itemOutput first was a atomic_uint64_t and now is a uint64_t.
The atomicwasn't necessary because itemOutput is accessed within
a mutex access, i.e. it is surrounded with a lock() and unlock()
which itself have a acquire and release behaviour, so I itemOutput
doesn't need to be atomic.
On 11/11/2023 2:41 AM, Bonita Montero wrote:
I think I've put the finishing touches to the code now. For the mutex[...]
part I introduced spinning, which I adopted from glibc. Spinning usually
Food for thought... I learned something really neat over on comp.arch
wrt Lynn Wheeler many years ago. Basically, why spin doing nothing? Oh,
you use a yield... Well, that is still doing nothing. Think of a spin
along the lines of:
we try to use accomplished work as a backoff/yield for a spin...
<quick pseudo-code>
______________
void lock()
{
while (! mutex_trylock())
{
// try to do some "other" work as a
// yield, in a sense... Hummm.... ;^)
if (! try_to_do_some__other__work())
{
// failed to do some other work, lock it...
mutex_lock();
break;
}
}
// we are locked! =^D
}
void unlock()
{
mutex_unlock();
}
______________
Well, this can be beneficial in certain setups...
On 2023-11-14, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote:
Kaz Kylheku wrote:
Because of the situation that the thread which was signaled isPlease see my response to your other post. "as-if" calling of
trying to acquire the mutex, which, stupidly, the signaling thread
is still holding. So, oops, back it goes into suspended state, and we
have to context switch to the mutex holder which has to release the
mutex and then switch to that signaled thread again.
pthread_mutex_lock does not prescribe actually calling it. Nothing in
the standard prevents pthread_cond_signal from doing all the job of
stuffing the unblocked threads to the mutex waiting list in accordance
with some scheduling policy.
Have you noticed how no mutex appears in the pthread_cond_signal API?
If you say so. I have not had enough time to study up on your code. Btw,
are you finished with any bug fixes? Are you sure it might not have any spinning out of control aspects to it? If I do model it, we need to get
to a concrete version of it, you say this is it, I say okay, call it BonitaMonitorVersion1. Fair enough?
On 11/13/2023 10:44 PM, Bonita Montero wrote:
Am 14.11.2023 um 06:21 schrieb Chris M. Thomasson:
You mean a word wrt the arch, or uint64_t on a 32-bit system?
itemOutput first was a atomic_uint64_t and now is a uint64_t.
The atomicwasn't necessary because itemOutput is accessed within
a mutex access, i.e. it is surrounded with a lock() and unlock()
which itself have a acquire and release behaviour, so I itemOutput
doesn't need to be atomic.
If you say so. I have not had enough time to study up on your code. Btw,
are you finished with any bug fixes? Are you sure it might not have any spinning out of control aspects to it? If I do model it, we need to get
to a concrete version of it, you say this is it, I say okay, call it BonitaMonitorVersion1. Fair enough?
https://youtu.be/T_U3Zdv8to8
Am 14.11.2023 um 07:51 schrieb Chris M. Thomasson:
If you say so. I have not had enough time to study up on your code.
Btw, are you finished with any bug fixes? Are you sure it might not
have any spinning out of control aspects to it? If I do model it, we
need to get to a concrete version of it, you say this is it, I say
okay, call it BonitaMonitorVersion1. Fair enough?
I've got a class thead_queue ...
Am 14.11.2023 um 07:51 schrieb Chris M. Thomasson:
If you say so. I have not had enough time to study up on your code.
Btw, are you finished with any bug fixes? Are you sure it might not
have any spinning out of control aspects to it? If I do model it, we
need to get to a concrete version of it, you say this is it, I say
okay, call it BonitaMonitorVersion1. Fair enough?
I've got a class thead_queue which I used for years. I changed it to
use my monitor instead a mutex plus condition variable. And the thead
_queue is used a lot and the code that used it works as before. That's
so much randomized synchronization for that that I for sure don't need
any Ralacy or whatever.
Am 14.11.2023 um 08:00 schrieb Bonita Montero:[...]
Am 14.11.2023 um 07:51 schrieb Chris M. Thomasson:
If you say so. I have not had enough time to study up on your code.
Btw, are you finished with any bug fixes? Are you sure it might not
have any spinning out of control aspects to it? If I do model it, we
need to get to a concrete version of it, you say this is it, I say
okay, call it BonitaMonitorVersion1. Fair enough?
I've got a class thead_queue ...
This is my thread_queue in the version where I didn't use my monitor:
Concepts rock !
On 11/11/2023 8:40 PM, Bonita Montero wrote:
Am 11.11.2023 um 20:42 schrieb Chris M. Thomasson:
Is that yet another bug correction? Remember my advise, get it
working then try to make it faster.
The code immediately crashed because of an exception;
easiest debugging.
Yet, you missed it? Actually, I am not quite sure how to parse your
response. I have not had the free time to port your code over to a
Relacy test unit, yet...
:^)
Yet, you missed it? Actually, I am not quite sure how to parse your
response. I have not had the free time to port your code over to a
Relacy test unit, yet...
Am 12.11.2023 um 21:46 schrieb Chris M. Thomasson:
Yet, you missed it? Actually, I am not quite sure how to parse your
response. I have not had the free time to port your code over to a
Relacy test unit, yet...
Do you really think your Relacy would have helped with my missing "!"
with the initializtion - at a point where I didn't any synchronization
at all ?
My Relacy?
Humm... Btw, my friend created it. Fwiw, I even helped him find some interesting issues it had during its very early phase. I found a couple
of bugs in Relacy! lol. Anyway, your missing "!"? Huh?
Am 14.11.2023 um 10:21 schrieb Chris M. Thomasson:
My Relacy?
Because you love it so much beyond necessity.
Humm... Btw, my friend created it. Fwiw, I even helped him find some
interesting issues it had during its very early phase. I found a
couple of bugs in Relacy! lol. Anyway, your missing "!"? Huh?
My monitor is only 230 lines of code and easy to understand; no
necessity for Relacy.
And I'm using my readers-writer-lock with
configurable priority for writers and readers for years without
having applied Relacy to it.
So, you are finished with any future on the fly corrections, right?
Kaz Kylheku wrote:
On 2023-11-13, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote: >>> Kaz Kylheku wrote:
If you're using POSIX mutexes and conditions, you should callThis is recommended against by the standard for the same reason why Java >>> implements Hoare monitor behavior. Citation:
pthread_cond_signal and pthread_cond_broadcast outside of the mutex,
whenever possible.
"
The pthread_cond_broadcast() or pthread_cond_signal() functions may be
called by a thread whether or not it currently owns the mutex that >>> threads calling pthread_cond_wait() or pthread_cond_timedwait() have
associated with the condition variable during their waits; however, if
predictable scheduling behavior is required, then that mutex shall be >>> locked by the thread calling pthread_cond_broadcast() or
pthread_cond_signal().
"
But that text is stupid/defective, because you will not actually get
predictable scheduling behavior just by doing that.
This is POSIX text that IIRC was a compromise with real-time (RT) guys.
Java has thread priorities so it is formally relevant (could be relevant
in some implementations, too; did not really check). RT guys don't like >condvars in principle as they are a "gateway drug" to all kinds of prio >inversions so this was a compromise that permitted the condvar to get to >POSIX. The meaning of the spec is to prevent priority inversion when
running on one CPU. An example problematic scenario is as follows:
1. Higher-prio thread A grabs mutex and starts waiting for an event
(say, posted to a queue that's currently empty). The mutex is released
at this time to allow posting the event (the standard behavior of >pthread_cond_wait()).
2. Now that the A is not runnable, a lower-prio thread B can also run
and suppose it also wants event from same queue.
3. Thread C grabs mutex, posts event to the queue, releases the mutex
4. Before thread C manages to signal the condvar (and by that wake up
thread A), thread B grabs the lock and steals the event. Higher-prio
thread A stays waiting for the event -- which is what RT guys hate.
With the behavior recommended by the standard, thread C will first
notify condvar, by that making thread A runnable and thread A will grab
the event.
Am 14.11.2023 um 06:21 schrieb Chris M. Thomasson:
You mean a word wrt the arch, or uint64_t on a 32-bit system?
itemOutput first was a atomic_uint64_t and now is a uint64_t.
The atomicwasn't necessary because itemOutput is accessed within
a mutex access, i.e. it is surrounded with a lock() and unlock()
which itself have a acquire and release behaviour, so I itemOutput
doesn't need to be atomic.
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 14.11.2023 um 06:21 schrieb Chris M. Thomasson:
You mean a word wrt the arch, or uint64_t on a 32-bit system?
itemOutput first was a atomic_uint64_t and now is a uint64_t.
The atomicwasn't necessary because itemOutput is accessed within
a mutex access, i.e. it is surrounded with a lock() and unlock()
which itself have a acquire and release behaviour, so I itemOutput
doesn't need to be atomic.
In most commonly used architectures a 64-bit load is single-copy
atomic regardless of any external synchronization (e.g. a mutex,
spin-lock or semaphore).
Am 14.11.2023 um 16:18 schrieb Scott Lurndal:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 14.11.2023 um 06:21 schrieb Chris M. Thomasson:
You mean a word wrt the arch, or uint64_t on a 32-bit system?
itemOutput first was a atomic_uint64_t and now is a uint64_t.
The atomicwasn't necessary because itemOutput is accessed within
a mutex access, i.e. it is surrounded with a lock() and unlock()
which itself have a acquire and release behaviour, so I itemOutput
doesn't need to be atomic.
In most commonly used architectures a 64-bit load is single-copy
atomic regardless of any external synchronization (e.g. a mutex,
spin-lock or semaphore).
Maybe, but you can't rely on that. If you have a 32 bit platform
I'm not aware of any 32-bit platform that supports 64-bit
accesses (other than via two 32-bit accesses).
If I do a 64 bit atomic store with MSVC or clang-cl on a 32 bit
platform it stores the value in the stack, loads it with SSE and
stores it atomically.
Am 14.11.2023 um 11:08 schrieb Chris M. Thomasson:
So, you are finished with any future on the fly corrections, right?
I'm currently not missing anything with the code.
On 11/14/2023 2:23 AM, Bonita Montero wrote:
Am 14.11.2023 um 11:08 schrieb Chris M. Thomasson:
So, you are finished with any future on the fly corrections, right?
I'm currently not missing anything with the code.
Okay, can you please make a new post that contains the finished code?
Thanks.
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 14.11.2023 um 16:18 schrieb Scott Lurndal:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 14.11.2023 um 06:21 schrieb Chris M. Thomasson:
You mean a word wrt the arch, or uint64_t on a 32-bit system?
itemOutput first was a atomic_uint64_t and now is a uint64_t.
The atomicwasn't necessary because itemOutput is accessed within
a mutex access, i.e. it is surrounded with a lock() and unlock()
which itself have a acquire and release behaviour, so I itemOutput
doesn't need to be atomic.
In most commonly used architectures a 64-bit load is single-copy
atomic regardless of any external synchronization (e.g. a mutex,
spin-lock or semaphore).
Maybe, but you can't rely on that. If you have a 32 bit platform
32-bit platform is somewhat uncommon (outside of specialty microcontrollers like the Cortex-M7).
I'm not aware of any 32-bit platform that supports 64-bit
accesses (other than via two 32-bit accesses).
With x86_64 and AArch64 you _can_ rely on it. And we do.
On 11/14/2023 8:09 AM, Scott Lurndal wrote:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 14.11.2023 um 16:18 schrieb Scott Lurndal:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 14.11.2023 um 06:21 schrieb Chris M. Thomasson:
You mean a word wrt the arch, or uint64_t on a 32-bit system?
itemOutput first was a atomic_uint64_t and now is a uint64_t.
The atomicwasn't necessary because itemOutput is accessed within
a mutex access, i.e. it is surrounded with a lock() and unlock()
which itself have a acquire and release behaviour, so I itemOutput
doesn't need to be atomic.
In most commonly used architectures a 64-bit load is single-copy
atomic regardless of any external synchronization (e.g. a mutex,
spin-lock or semaphore).
Maybe, but you can't rely on that. If you have a 32 bit platform
32-bit platform is somewhat uncommon (outside of specialty microcontrollers
like the Cortex-M7).
I'm not aware of any 32-bit platform that supports 64-bit
accesses (other than via two 32-bit accesses).
Well, we have cmpxchg8b on 32-bit Intel...
On 11/14/2023 8:09 AM, Scott Lurndal wrote:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 14.11.2023 um 16:18 schrieb Scott Lurndal:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 14.11.2023 um 06:21 schrieb Chris M. Thomasson:
You mean a word wrt the arch, or uint64_t on a 32-bit system?
itemOutput first was a atomic_uint64_t and now is a uint64_t.
The atomicwasn't necessary because itemOutput is accessed within
a mutex access, i.e. it is surrounded with a lock() and unlock()
which itself have a acquire and release behaviour, so I itemOutput
doesn't need to be atomic.
In most commonly used architectures a 64-bit load is single-copy
atomic regardless of any external synchronization (e.g. a mutex,
spin-lock or semaphore).
Maybe, but you can't rely on that. If you have a 32 bit platform
32-bit platform is somewhat uncommon (outside of specialty
microcontrollers
like the Cortex-M7).
I'm not aware of any 32-bit platform that supports 64-bit
accesses (other than via two 32-bit accesses).
Well, we have cmpxchg8b on 32-bit Intel...
With x86_64 and AArch64 you _can_ rely on it. And we do.
On 2023-11-14, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote:
Kaz Kylheku wrote:
Because of the situation that the thread which was signaled isPlease see my response to your other post. "as-if" calling of
trying to acquire the mutex, which, stupidly, the signaling thread
is still holding. So, oops, back it goes into suspended state, and we
have to context switch to the mutex holder which has to release the
mutex and then switch to that signaled thread again.
pthread_mutex_lock does not prescribe actually calling it. Nothing in
the standard prevents pthread_cond_signal from doing all the job of
stuffing the unblocked threads to the mutex waiting list in accordance
with some scheduling policy.
Have you noticed how no mutex appears in the pthread_cond_signal API?
On 2023-11-14, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote:
"as-if" and "according to the scheduling policy (if applicable)" here
are important. The standard intent may be to permit only the threads
that are "unblocked" contend for the mutex -- as opposed to all
non-blocked threads.
It's possible that only one thread is unblocked by a
pthread_cond_signal. It takes at least two parties to contend for
something.
On 11/13/2023 9:28 PM, Chris M. Thomasson wrote:It can, it's just that the desired scheduling policy cannot be
On 11/13/2023 7:27 PM, Kaz Kylheku wrote:
On 2023-11-14, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo>
wrote:
"as-if" and "according to the scheduling policy (if applicable)" here
are important. The standard intent may be to permit only the threads
that are "unblocked" contend for the mutex -- as opposed to all
non-blocked threads.
It's possible that only one thread is unblocked by a
pthread_cond_signal. It takes at least two parties to contend for
something.
A signalling thread does its thing while holding the mutex... Well, it
hears the following playing in the background:
https://youtu.be/7YvAYIJSSZY
A condvar that cannot signal/broadcast from outside of a held mutex is
broken by default.
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> writes:This has been an alternative for a while but traditionally RT is built
Kaz Kylheku wrote:
On 2023-11-13, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote:
Kaz Kylheku wrote:
If you're using POSIX mutexes and conditions, you should callThis is recommended against by the standard for the same reason why Java >>>> implements Hoare monitor behavior. Citation:
pthread_cond_signal and pthread_cond_broadcast outside of the mutex, >>>>> whenever possible.
"
The pthread_cond_broadcast() or pthread_cond_signal() functions may be >>>> called by a thread whether or not it currently owns the mutex that >>>> threads calling pthread_cond_wait() or pthread_cond_timedwait() have
associated with the condition variable during their waits; however, if >>>> predictable scheduling behavior is required, then that mutex shall be >>>> locked by the thread calling pthread_cond_broadcast() or
pthread_cond_signal().
"
But that text is stupid/defective, because you will not actually get
predictable scheduling behavior just by doing that.
This is POSIX text that IIRC was a compromise with real-time (RT) guys.
Java has thread priorities so it is formally relevant (could be relevant
in some implementations, too; did not really check). RT guys don't like
condvars in principle as they are a "gateway drug" to all kinds of prio
inversions so this was a compromise that permitted the condvar to get to
POSIX. The meaning of the spec is to prevent priority inversion when
running on one CPU. An example problematic scenario is as follows:
1. Higher-prio thread A grabs mutex and starts waiting for an event
(say, posted to a queue that's currently empty). The mutex is released
at this time to allow posting the event (the standard behavior of
pthread_cond_wait()).
2. Now that the A is not runnable, a lower-prio thread B can also run
and suppose it also wants event from same queue.
3. Thread C grabs mutex, posts event to the queue, releases the mutex
4. Before thread C manages to signal the condvar (and by that wake up
thread A), thread B grabs the lock and steals the event. Higher-prio
thread A stays waiting for the event -- which is what RT guys hate.
With the behavior recommended by the standard, thread C will first
notify condvar, by that making thread A runnable and thread A will grab
the event.
Clearly the application should have used a queue per priority in
this case.
Am 09.11.2023 um 06:48 schrieb Chris M. Thomasson:
On 11/8/2023 9:45 PM, Bonita Montero wrote:
Am 09.11.2023 um 06:44 schrieb Chris M. Thomasson:
Wait morphing is not in the realm of the compiler. It's in the kernel.
Read this:
https://stackoverflow.com/questions/45163701/which-os-platforms-implement-wait-morphing-optimization
Wait morphing can be highly beneficial.
Wait morphing isn't necessary under Win32 since you can wait
for the mutexe's binary semaphore and for the condvar's counting
semaphore in one step with WaitForMultipleObjects. Unfortunately
there's nothing under Linux like that.
Well, we have cmpxchg8b on 32-bit Intel...
On 11/14/2023 2:23 AM, Bonita Montero wrote:
Am 14.11.2023 um 11:08 schrieb Chris M. Thomasson:
So, you are finished with any future on the fly corrections, right?
I'm currently not missing anything with the code.
Okay, can you please make a new post that contains the finished code?
Bonita Montero wrote:
Am 09.11.2023 um 06:48 schrieb Chris M. Thomasson:Not true. A Linux program can wait for any number of eventfd semaphores
On 11/8/2023 9:45 PM, Bonita Montero wrote:
Am 09.11.2023 um 06:44 schrieb Chris M. Thomasson:
Wait morphing is not in the realm of the compiler. It's in the kernel. >>>>Read this:
https://stackoverflow.com/questions/45163701/which-os-platforms-implement-wait-morphing-optimization
Wait morphing can be highly beneficial.
Wait morphing isn't necessary under Win32 since you can wait
for the mutexe's binary semaphore and for the condvar's counting
semaphore in one step with WaitForMultipleObjects. Unfortunately
there's nothing under Linux like that.
that can be used as either binary or a counting one.
Am 14.11.2023 um 21:25 schrieb Chris M. Thomasson:
Well, we have cmpxchg8b on 32-bit Intel...
That's what I also thought, i.e. you can make a 64 bit store with that.
But that's for sure much slower than the trick with the x87-FPU I've
shown.
Kaz Kylheku wrote:
On 2023-11-14, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo>Of course but so what? Nothing prevents the implementation from listing
wrote:
Kaz Kylheku wrote:
Because of the situation that the thread which was signaled isPlease see my response to your other post. "as-if" calling of
trying to acquire the mutex, which, stupidly, the signaling thread
is still holding. So, oops, back it goes into suspended state, and we
have to context switch to the mutex holder which has to release the
mutex and then switch to that signaled thread again.
pthread_mutex_lock does not prescribe actually calling it. Nothing in
the standard prevents pthread_cond_signal from doing all the job of
stuffing the unblocked threads to the mutex waiting list in accordance
with some scheduling policy.
Have you noticed how no mutex appears in the pthread_cond_signal API?
the temporarily released mutices of the waiting pthread_cond_wait
callers in the cond var where pthread_cond_signal can access them.
Or, possibly even better, keeping a pointer to them with the threads waiting for the condvar (there can only be at most one such temporarily released mutex per the waiting thread). And the threads waiting for the condvar are accessible for the pthread_cond_signal according to the spec.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 11/14/2023 8:09 AM, Scott Lurndal wrote:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 14.11.2023 um 16:18 schrieb Scott Lurndal:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 14.11.2023 um 06:21 schrieb Chris M. Thomasson:
You mean a word wrt the arch, or uint64_t on a 32-bit system?
itemOutput first was a atomic_uint64_t and now is a uint64_t.
The atomicwasn't necessary because itemOutput is accessed within
a mutex access, i.e. it is surrounded with a lock() and unlock()
which itself have a acquire and release behaviour, so I itemOutput >>>>>> doesn't need to be atomic.
In most commonly used architectures a 64-bit load is single-copy
atomic regardless of any external synchronization (e.g. a mutex,
spin-lock or semaphore).
Maybe, but you can't rely on that. If you have a 32 bit platform
32-bit platform is somewhat uncommon (outside of specialty microcontrollers
like the Cortex-M7).
I'm not aware of any 32-bit platform that supports 64-bit
accesses (other than via two 32-bit accesses).
Well, we have cmpxchg8b on 32-bit Intel...
For which a single-copy atomic semantic property is implicit
in the operation.
As BM pointed out, once SSE et al showed up, there was a way to
do some 64-bit loads. Not sure they're architecturally
required to be single-copy atomic, however.
On 11/14/2023 5:47 PM, Pavel wrote:
Chris M. Thomasson wrote:
On 11/13/2023 9:28 PM, Chris M. Thomasson wrote:It can, it's just that the desired scheduling policy cannot be
On 11/13/2023 7:27 PM, Kaz Kylheku wrote:
On 2023-11-14, Pavel
<pauldontspamtolk@removeyourself.dontspam.yahoo> wrote:
"as-if" and "according to the scheduling policy (if applicable)" here >>>>>> are important. The standard intent may be to permit only the threads >>>>>> that are "unblocked" contend for the mutex -- as opposed to all
non-blocked threads.
It's possible that only one thread is unblocked by a
pthread_cond_signal. It takes at least two parties to contend for
something.
A signalling thread does its thing while holding the mutex... Well,
it hears the following playing in the background:
https://youtu.be/7YvAYIJSSZY
A condvar that cannot signal/broadcast from outside of a held mutex
is broken by default.
*effectively* applied if a program signal outside of that mutex.
E.g. in some scenario a higher-prio thread could stay indefinitely
starved by the lower-prio thread, regardless of the thread library
implementation.
Afaict, it is an implementation detail. Say, SCHED_FIFO, the impl shall strive to honor this. If it has to use a bakery algorithm to do it, so
be it.
Am 14.11.2023 um 21:27 schrieb Chris M. Thomasson:
On 11/14/2023 2:23 AM, Bonita Montero wrote:
Am 14.11.2023 um 11:08 schrieb Chris M. Thomasson:
So, you are finished with any future on the fly corrections, right?
I'm currently not missing anything with the code.
Okay, can you please make a new post that contains the finished code?
I already posted the finished code in two parts with this little
correction (missing "!"). The xhandle.h is still the same.
Chris M. Thomasson wrote:
On 11/13/2023 9:28 PM, Chris M. Thomasson wrote:It can, it's just that the desired scheduling policy cannot be
On 11/13/2023 7:27 PM, Kaz Kylheku wrote:
On 2023-11-14, Pavel
<pauldontspamtolk@removeyourself.dontspam.yahoo> wrote:
"as-if" and "according to the scheduling policy (if applicable)" here >>>>> are important. The standard intent may be to permit only the threads >>>>> that are "unblocked" contend for the mutex -- as opposed to all
non-blocked threads.
It's possible that only one thread is unblocked by a
pthread_cond_signal. It takes at least two parties to contend for
something.
A signalling thread does its thing while holding the mutex... Well,
it hears the following playing in the background:
https://youtu.be/7YvAYIJSSZY
A condvar that cannot signal/broadcast from outside of a held mutex is
broken by default.
*effectively* applied if a program signal outside of that mutex.
E.g. in some scenario a higher-prio thread could stay indefinitely
starved by the lower-prio thread, regardless of the thread library implementation.
Chris M. Thomasson wrote:
On 11/13/2023 9:28 PM, Chris M. Thomasson wrote:It can, it's just that the desired scheduling policy cannot be
On 11/13/2023 7:27 PM, Kaz Kylheku wrote:
On 2023-11-14, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo>
wrote:
"as-if" and "according to the scheduling policy (if applicable)" here >>>>> are important. The standard intent may be to permit only the threads >>>>> that are "unblocked" contend for the mutex -- as opposed to all
non-blocked threads.
It's possible that only one thread is unblocked by a
pthread_cond_signal. It takes at least two parties to contend for
something.
A signalling thread does its thing while holding the mutex... Well, it
hears the following playing in the background:
https://youtu.be/7YvAYIJSSZY
A condvar that cannot signal/broadcast from outside of a held mutex is
broken by default.
*effectively* applied if a program signal outside of that mutex.
E.g. in some scenario a higher-prio thread could stay indefinitely
starved by the lower-prio thread, regardless of the thread library implementation.
Correction? Just post the 100% finished code in a brand new thread.
Are you sure its 100% atomic for use in multi-thread sync algorithms?
Am 15.11.2023 um 21:21 schrieb Chris M. Thomasson:
Correction? Just post the 100% finished code in a brand new thread.
I've postet everything that is necessary, you only have to add a "!".
On 11/15/2023 7:00 PM, Bonita Montero wrote:
Am 15.11.2023 um 21:21 schrieb Chris M. Thomasson:
Correction? Just post the 100% finished code in a brand new thread.
I've postet everything that is necessary, you only have to add a "!".
Wow... Anyway, where do I add this "!"?
On 11/14/2023 5:26 PM, Pavel wrote:
Kaz Kylheku wrote:
On 2023-11-14, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo>Of course but so what? Nothing prevents the implementation from
wrote:
Kaz Kylheku wrote:
Because of the situation that the thread which was signaled isPlease see my response to your other post. "as-if" calling of
trying to acquire the mutex, which, stupidly, the signaling thread
is still holding. So, oops, back it goes into suspended state, and we >>>>> have to context switch to the mutex holder which has to release the
mutex and then switch to that signaled thread again.
pthread_mutex_lock does not prescribe actually calling it. Nothing in
the standard prevents pthread_cond_signal from doing all the job of
stuffing the unblocked threads to the mutex waiting list in accordance >>>> with some scheduling policy.
Have you noticed how no mutex appears in the pthread_cond_signal API?
listing the temporarily released mutices of the waiting
pthread_cond_wait callers in the cond var where pthread_cond_signal
can access them.
Or, possibly even better, keeping a pointer to them with the threads
waiting for the condvar (there can only be at most one such
temporarily released mutex per the waiting thread). And the threads
waiting for the condvar are accessible for the pthread_cond_signal
according to the spec.
Just as long as the implementation works wrt calling pthread_cond_signal/broadcast outside of the mutex. If not, it is broken.
Wow... Anyway, where do I add this "!"?
On 2023-11-15, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote:
Chris M. Thomasson wrote:
On 11/13/2023 9:28 PM, Chris M. Thomasson wrote:It can, it's just that the desired scheduling policy cannot be
On 11/13/2023 7:27 PM, Kaz Kylheku wrote:
On 2023-11-14, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> >>>>> wrote:
"as-if" and "according to the scheduling policy (if applicable)" here >>>>>> are important. The standard intent may be to permit only the threads >>>>>> that are "unblocked" contend for the mutex -- as opposed to all
non-blocked threads.
It's possible that only one thread is unblocked by a
pthread_cond_signal. It takes at least two parties to contend for
something.
A signalling thread does its thing while holding the mutex... Well, it >>>> hears the following playing in the background:
https://youtu.be/7YvAYIJSSZY
A condvar that cannot signal/broadcast from outside of a held mutex is
broken by default.
*effectively* applied if a program signal outside of that mutex.
E.g. in some scenario a higher-prio thread could stay indefinitely
starved by the lower-prio thread, regardless of the thread library
implementation.
I don't see what difference it can actually make, other than in
situations when a thread receives a priority boost while holding a
mutex.
Only one of these is true: (1) either the pthread_cond_signal and pthread_cond_broadcast functions transfer threads from waiting on the condition to waiting on the mutex, or (2) they don't: threads are woken,
and have to execute an operation equivalent to pthread_mutex_lock.
(Though there is no mutex argument in the API, the thread is waiting
with respect to a particular mutex. Each thread waiting on the same
condition could nominate a different mutex. So for each thread waiting
on a condition, we know which mutex it released in doing so and can
transfer it to wait on the mutex.)
If the pthread_cond_signal function transfers a thread from the
condition to the mutex according to (1), then everything is cool with
regard to scheduling.
Whether we have this:
pthread_mutex_unlock(&m);
pthread_cond_signal(&c);
...
// re-acquire
pthread_mutex_lock(&m);
or this:
pthread_cond_signal(&c);
pthread_mutex_unlock(&m);
...
// re-acquire
pthread_mutex_lock(&m);
the most important thing is that the waiting threads are already
transferred to waiting on the mutex, before the signaling thread call
tries to re-acquire the mutex.
I.e. the woken threads always reach the mutex wait first, regardless of
these two orders of operations on the part of the signaling thread.
On the other hand, if the pthread_cond_signal operation just wakes up
the threads, such that they themselves have to call the equivalent of pthread_mutex_lock to reacquire the mutex, we do not gain any special guarantees in one order or the other. Under either order of the
statements, the signaling thread can snatch the mutex away from the
signaled threads, when reaching the pthread_mutex_lock call,
even if it is a low priority thread and the others are high.
Now with real-time priorities and mutexes that prevent priority
inversion, we could have the following situation:
While a low-priority thread holds a mutex, it is temporarily boosted to
the highest priority from among the set of threads waiting for that
mutex.
There we have a difference between signaling inside or outside, the
reason being that when the thread leaves the mutex to signal outside, it loses the temporary priority boost. That could lead to an undue delay in signaling the condition.
The statement in the POSIX standard about predictable scheduling
behavior is like recommending sleep calls to for obtaining more
predictable behavior in a program riddled with race conditions.
If I'm an implementor reading that statement, I cannot infer any
concrete requirements about what it is that I'm supposed to do in pthread_cond_signal to bring about more predictable scheduling.
Specifications should give specific requirements, not vague opinions.
I am unsure where from that discussion of implementation came. The
*spec* permits this (signalling without holding the mutex), just warns
that a predictable scheduling behavior cannot be achieved then.
Because of the situation that the thread which was signaled is
trying to acquire the mutex, which, stupidly, the signaling thread
is still holding. So, oops, back it goes into suspended state, and
we have to context switch to the mutex holder which has to release
the mutex and then switch to that signaled thread again.
Am 15.11.2023 um 21:08 schrieb Chris M. Thomasson:
Are you sure its 100% atomic for use in multi-thread sync algorithms?
If MSVC generates that code it's atomic.
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 15.11.2023 um 21:08 schrieb Chris M. Thomasson:
Are you sure its 100% atomic for use in multi-thread sync algorithms?
If MSVC generates that code it's atomic.
No, if Intel architecture documentation specifies that it is
single-copy atomic, then it is single-copy atomic.
MSVC is just a poor-to-middling C compiler.
Am 16.11.2023 um 16:02 schrieb Scott Lurndal:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 15.11.2023 um 21:08 schrieb Chris M. Thomasson:
Are you sure its 100% atomic for use in multi-thread sync algorithms?
If MSVC generates that code it's atomic.
No, if Intel architecture documentation specifies that it is
single-copy atomic, then it is single-copy atomic.
MSVC relies for sure on the right behaviour.
MSVC is just a poor-to-middling C compiler.
MSVC has the strongest C++20-conformance but the weakest optimizer.
Am 16.11.2023 um 04:10 schrieb Chris M. Thomasson:
Wow... Anyway, where do I add this "!"?
You don't have to change it because the Windows code was correct
anyway.
On 11/12/2023 4:29 PM, Pavel wrote:
Kaz Kylheku wrote:
On 2023-11-12, Bonita Montero <Bonita.Montero@gmail.com> wrote:She doesn't. See my citation in response to her post for the reference
No, Java and .net keep holding the mutex while doing a notify().
That's called a Mesa monitor.
I don't suspect that is part of Mesa semantics. (It's definitely part of >>> Hoare semantics.) Do you have a reference?
to the contrary.
This is recommended against by the standard for the same reason why
Since under Mesa semantics, threads re-acquire the mutex with fewer
guarantees and must re-test the desired condition, Mesa semantics
supports the more efficient protocol of signaling outside of the
monitor.
If you're using POSIX mutexes and conditions, you should call
pthread_cond_signal and pthread_cond_broadcast outside of the mutex,
whenever possible.
Java implements Hoare monitor behavior. Citation:
"
The pthread_cond_broadcast() or pthread_cond_signal() functions may be
called by a thread whether or not it currently owns the mutex
that threads calling pthread_cond_wait() or pthread_cond_timedwait()
have associated with the condition variable during their waits;
however, if predictable scheduling behavior is required, then that
mutex shall be locked by the thread calling pthread_cond_broadcast()
or pthread_cond_signal(). > "
(In a nutshell, if you're going to be telling some thread(s) to go ahead >>> and grab a mutex, get the hell out of their way first).
Basically, if you signal while locked then another waiting thread is
going to try to acquire the mutex that is already locked by the
signalling thread, instant contention. However, wait morphing techniques
can be used to handle this since a mutex and a condvar are very intimate
with each other anyway. Usually, signalling outside of the mutex is ideal.
On 2023-11-16, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote:
I am unsure where from that discussion of implementation came. The
*spec* permits this (signalling without holding the mutex), just warns
that a predictable scheduling behavior cannot be achieved then.
The spec is supposed to tell implementors what to make.
Loose wording like this is dangerous. An implementor is free to
interpret it like this: whenever a program calls pthread_cond_signal,
and it so happens that the calling threads owns no mutex whatsoever, the implementation is free to set a flag somewhere, based on which it will willfully damage the integrity of the scheduling implementation somehow,
so that it behaves like crap.
Huh? Do I have to correct your code with that "!" or not?
Kaz Kylheku wrote:
On 2023-11-16, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote: >>> I am unsure where from that discussion of implementation came. TheIf your complaint is about "predictable scheduling behavior" not being >defined in the standard, I understand and sympathize. It could be better >defined. When POSIX threads were developed, this was kinda obvious
*spec* permits this (signalling without holding the mutex), just warns
that a predictable scheduling behavior cannot be achieved then.
The spec is supposed to tell implementors what to make.
Loose wording like this is dangerous. An implementor is free to
interpret it like this: whenever a program calls pthread_cond_signal,
and it so happens that the calling threads owns no mutex whatsoever, the
implementation is free to set a flag somewhere, based on which it will
willfully damage the integrity of the scheduling implementation somehow,
so that it behaves like crap.
because RT guys required that and they know what they mean by that
(meaning -- more or less agree). This is not a good excuse for not
spelling it in the standard of course.
See if this old posting of David Butenhof, one of the spec authors may >clarify the concept:
https://austin-group-l.opengroup.narkive.com/lKcmfoRI/predictable-scheduling-behavior-in-pthread-cond-broadcast
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> writes:
Kaz Kylheku wrote:
On 2023-11-16, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote:If your complaint is about "predictable scheduling behavior" not being
I am unsure where from that discussion of implementation came. The
*spec* permits this (signalling without holding the mutex), just warns >>>> that a predictable scheduling behavior cannot be achieved then.
The spec is supposed to tell implementors what to make.
Loose wording like this is dangerous. An implementor is free to
interpret it like this: whenever a program calls pthread_cond_signal,
and it so happens that the calling threads owns no mutex whatsoever, the >>> implementation is free to set a flag somewhere, based on which it will
willfully damage the integrity of the scheduling implementation somehow, >>> so that it behaves like crap.
defined in the standard, I understand and sympathize. It could be better
defined. When POSIX threads were developed, this was kinda obvious
because RT guys required that and they know what they mean by that
(meaning -- more or less agree). This is not a good excuse for not
spelling it in the standard of course.
See if this old posting of David Butenhof, one of the spec authors may
clarify the concept:
https://austin-group-l.opengroup.narkive.com/lKcmfoRI/predictable-scheduling-behavior-in-pthread-cond-broadcast
When David wrote that, multiprocessor systems were still rare and
limited to very expensive systems (e.g. Sequent) (and for the most
part, weren't running real-time code). I was on the X/Open working group for a few years during that time period, and one of my collegues at
SGI was part of the 1003.4 working group.
thirty years later, pthread_cond_t is heavily used by non-realtime
code, where such priority inversions (usually very transient) don't
matter.
For the number of cases where pthread_cond_t is used in hard
real-time code, the appropriate techniques (i.e. holding the mutex
while signaling the condition) are available.
When David wrote that, multiprocessor systems were still rare and
On 2023-11-17, Scott Lurndal <scott@slp53.sl.home> wrote: >>>https://austin-group-l.opengroup.narkive.com/lKcmfoRI/predictable-scheduling-behavior-in-pthread-cond-broadcast
When David wrote that, multiprocessor systems were still rare and
The referenced discussion appears to be from early 2010; maybe
he was reiterating something from an earlier time?
Kaz Kylheku <864-117-4973@kylheku.com> writes:
On 2023-11-17, Scott Lurndal <scott@slp53.sl.home> wrote: >>>>https://austin-group-l.opengroup.narkive.com/lKcmfoRI/predictable-scheduling-behavior-in-pthread-cond-broadcast
When David wrote that, multiprocessor systems were still rare and
The referenced discussion appears to be from early 2010; maybe
he was reiterating something from an earlier time?
The Posix 1003.4 (.4b - realtime and .4c - threads) work was in the
mid 90's. At that time, SMP systems were expensive and relatively
rare. My 2p octane workstation in 1998 was great, but uncommon even
in SGI engineering.
Am 15.11.2023 um 03:10 schrieb Pavel:
Bonita Montero wrote:
Am 09.11.2023 um 06:48 schrieb Chris M. Thomasson:Not true. A Linux program can wait for any number of eventfd
On 11/8/2023 9:45 PM, Bonita Montero wrote:
Am 09.11.2023 um 06:44 schrieb Chris M. Thomasson:
Wait morphing is not in the realm of the compiler. It's in the
kernel.
Read this:
https://stackoverflow.com/questions/45163701/which-os-platforms-implement-wait-morphing-optimization
Wait morphing can be highly beneficial.
Wait morphing isn't necessary under Win32 since you can wait
for the mutexe's binary semaphore and for the condvar's counting
semaphore in one step with WaitForMultipleObjects. Unfortunately
there's nothing under Linux like that.
semaphores that can be used as either binary or a counting one.
An eventfd can be a semaphore, but only one semaphore and not a set
like SysV semaphores. You can wait for multiple semaphores with poll
or select, but a change on one semaphore releases the waiting thread
whereas with Win32 you can wait for all conditions to be met at once.
There is no system call in UNIX to wait for many conditions to be met at once; but I do not see why it would be useful.
Am 18.11.2023 um 03:16 schrieb Pavel:what does it have to do with what I wrote?
There is no system call in UNIX to wait for many conditions to be met
at once; but I do not see why it would be useful.
poll() and wait() wait for at least one condition to be met.
Bonita Montero wrote:
Am 18.11.2023 um 03:16 schrieb Pavel:what does it have to do with what I wrote?
There is no system call in UNIX to wait for many conditions to be met
at once; but I do not see why it would be useful.
poll() and wait() wait for at least one condition to be met.
Again, what a system call that waits for many conditions to be met at
once can be useful for?
Bonita Montero wrote:
Am 18.11.2023 um 03:16 schrieb Pavel:what does it have to do with what I wrote?
There is no system call in UNIX to wait for many conditions to be met
at once; but I do not see why it would be useful.
poll() and wait() wait for at least one condition to be met.
Again, what a system call that waits for many conditions to be met at
once can be useful for?
Bonita Montero wrote:
Am 18.11.2023 um 03:16 schrieb Pavel:what does it have to do with what I wrote?
There is no system call in UNIX to wait for many conditions to be met
at once; but I do not see why it would be useful.
poll() and wait() wait for at least one condition to be met.
Again, what a system call that waits for many conditions to be met at
once can be useful for?
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> writes:
Bonita Montero wrote:
Am 18.11.2023 um 03:16 schrieb Pavel:what does it have to do with what I wrote?
There is no system call in UNIX to wait for many conditions to be met
at once; but I do not see why it would be useful.
poll() and wait() wait for at least one condition to be met.
Again, what a system call that waits for many conditions to be met at
once can be useful for?
Rendezvous.
e.g. pthread_barrier_wait.
On 11/18/2023 9:53 AM, Pavel wrote:
Bonita Montero wrote:
Am 18.11.2023 um 03:16 schrieb Pavel:what does it have to do with what I wrote?
There is no system call in UNIX to wait for many conditions to be met
at once; but I do not see why it would be useful.
poll() and wait() wait for at least one condition to be met.
Again, what a system call that waits for many conditions to be met at
once can be useful for?
select?
On 2023-11-18, Scott Lurndal <scott@slp53.sl.home> wrote:
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> writes:
Bonita Montero wrote:
Am 18.11.2023 um 03:16 schrieb Pavel:what does it have to do with what I wrote?
There is no system call in UNIX to wait for many conditions to be met >>>>> at once; but I do not see why it would be useful.
poll() and wait() wait for at least one condition to be met.
Again, what a system call that waits for many conditions to be met at >>>once can be useful for?
Rendezvous.
e.g. pthread_barrier_wait.
Also this:
while (!this_condition() && !that_condition() && !other_condition())
pthread_cond_wait(&cond, &mutex);
One condition variable can be used to wait for any subset of the
actual conditions over the shared variables protected by the mutex.
When I switched to a Win32 development job in the mid 1990's, it amused
me that Win32 had all these stupid things like WaitForMultipleObjects
(with a weird 64 limit), instead of just providing condition variables.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 11/18/2023 9:53 AM, Pavel wrote:
Bonita Montero wrote:
Am 18.11.2023 um 03:16 schrieb Pavel:what does it have to do with what I wrote?
There is no system call in UNIX to wait for many conditions to be met >>>>> at once; but I do not see why it would be useful.
poll() and wait() wait for at least one condition to be met.
Again, what a system call that waits for many conditions to be met at
once can be useful for?
select?
I took Pavel to mean 'wait for all conditions to be true' rather than
'wait for one or more conditions to be true'.
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> writes:Is it even useful? I got familiar with it first in late 80s while
Bonita Montero wrote:
Am 18.11.2023 um 03:16 schrieb Pavel:what does it have to do with what I wrote?
There is no system call in UNIX to wait for many conditions to be met
at once; but I do not see why it would be useful.
poll() and wait() wait for at least one condition to be met.
Again, what a system call that waits for many conditions to be met at
once can be useful for?
Rendezvous.
e.g. pthread_barrier_wait.
On 11/18/2023 1:47 PM, Scott Lurndal wrote:NP, Scott is correct, this was about "wait for many conditions to be met
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 11/18/2023 9:53 AM, Pavel wrote:
Bonita Montero wrote:
Am 18.11.2023 um 03:16 schrieb Pavel:what does it have to do with what I wrote?
There is no system call in UNIX to wait for many conditions to be met >>>>>> at once; but I do not see why it would be useful.
poll() and wait() wait for at least one condition to be met.
Again, what a system call that waits for many conditions to be met at
once can be useful for?
select?
I took Pavel to mean 'wait for all conditions to be true' rather than
'wait for one or more conditions to be true'.
Ahhh. I missed that. Sorry everybody! ;^o
On 2023-11-18, Scott Lurndal <scott@slp53.sl.home> wrote:
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> writes:
Bonita Montero wrote:
Am 18.11.2023 um 03:16 schrieb Pavel:what does it have to do with what I wrote?
There is no system call in UNIX to wait for many conditions to be met >>>>> at once; but I do not see why it would be useful.
poll() and wait() wait for at least one condition to be met.
Again, what a system call that waits for many conditions to be met at
once can be useful for?
Rendezvous.
e.g. pthread_barrier_wait.
Also this:
while (!this_condition() && !that_condition() && !other_condition())
pthread_cond_wait(&cond, &mutex);
One condition variable can be used to wait for any subset of the
actual conditions over the shared variables protected by the mutex.
When I switched to a Win32 development job in the mid 1990's, it amused
me that Win32 had all these stupid things like WaitForMultipleObjects
(with a weird 64 limit), instead of just providing condition variables.
Today, Microsoft provides condition variables.
Modules of a large program should use callbacks to notify that something
is ready. That's the most flexible API. The caller can build proper asynchronous control flows around that, or bind the callback to some signaling object according to how they see fit.
Say I have a module that works with three other modules that can spontaneously make some condition ready. If they all provide a callback,
I can set a flag in the callback and broadcast or signal a condition variable. Then I can have threads wait for all three things to be
ready, or any one of the three things.
Am 18.11.2023 um 20:24 schrieb Scott Lurndal:
e.g. pthread_barrier_wait.
pthread_barrier_wait is for multiple threads joining on one event,
not one thread waiting for multiple events as discussed.
e.g. pthread_barrier_wait.
On 2023-11-19, Bonita Montero <Bonita.Montero@gmail.com> wrote:
Am 18.11.2023 um 20:24 schrieb Scott Lurndal:
e.g. pthread_barrier_wait.
pthread_barrier_wait is for multiple threads joining on one event,
not one thread waiting for multiple events as discussed.
That is untrue; there are effectively N events in a barrier:
Am 19.11.2023 um 06:02 schrieb Kaz Kylheku:
On 2023-11-19, Bonita Montero <Bonita.Montero@gmail.com> wrote:
Am 18.11.2023 um 20:24 schrieb Scott Lurndal:
e.g. pthread_barrier_wait.
pthread_barrier_wait is for multiple threads joining on one event,
not one thread waiting for multiple events as discussed.
That is untrue; there are effectively N events in a barrier:
No, a barrier internally consists of an atomic which each thread
decrements
That's an implementation detail. ...
On 11/19/2023 3:05 AM, Bonita Montero wrote:
Am 19.11.2023 um 07:08 schrieb Kaz Kylheku:
That's an implementation detail. ...
That's how it works.
So from the scheduling / kernel perspective there's only one event.
I suspect that you are unfamiliar with how WaitForMultipleObjects
works... I remember a test for 50,000 concurrent connections, that was mentioned by Microsoft. It was testing events vs IOCP. Did you know that
they recommended altering the indexes of the events waited for by WaitForMultipleObjects? I remember it, is was a long time ago, 2001 ish, iirc.
Iirc, it was recommended to basically randomize, or shift the indexes.
God damn, I need to find that old post on msdn. Again, iirc, if we did
not do this, some events could starve in the server experiment.
The funny part is that the event based model performed pretty good, not
as scalable as IOCP, however, IOCP did not completely blow it out of the water wrt performance and throughput.
Am 19.11.2023 um 07:08 schrieb Kaz Kylheku:
That's an implementation detail. ...
That's how it works.
So from the scheduling / kernel perspective there's only one event.
On 11/19/2023 12:08 PM, Chris M. Thomasson wrote:
On 11/19/2023 3:05 AM, Bonita Montero wrote:
Am 19.11.2023 um 07:08 schrieb Kaz Kylheku:
That's an implementation detail. ...
That's how it works.
So from the scheduling / kernel perspective there's only one event.
I suspect that you are unfamiliar with how WaitForMultipleObjects
works... I remember a test for 50,000 concurrent connections, that was
mentioned by Microsoft. It was testing events vs IOCP. Did you know
that they recommended altering the indexes of the events waited for by
WaitForMultipleObjects? I remember it, is was a long time ago, 2001
ish, iirc.
Iirc, it was recommended to basically randomize, or shift the indexes.
God damn, I need to find that old post on msdn. Again, iirc, if we did
not do this, some events could starve in the server experiment.
The funny part is that the event based model performed pretty good,
not as scalable as IOCP, however, IOCP did not completely blow it out
of the water wrt performance and throughput.
After I read that msdn post, I basically created a proxy server. One
using events, and another using IOCP. IOCP beats it, but did not
slaughter it at that time. I found that to be interesting.
I suspect that you are unfamiliar with how WaitForMultipleObjects
works... ...
Chris M. Thomasson wrote:
On 11/18/2023 1:47 PM, Scott Lurndal wrote:NP, Scott is correct, this was about "wait for many conditions to be met
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 11/18/2023 9:53 AM, Pavel wrote:
Bonita Montero wrote:
Am 18.11.2023 um 03:16 schrieb Pavel:what does it have to do with what I wrote?
There is no system call in UNIX to wait for many conditions to be >>>>>>> met
at once; but I do not see why it would be useful.
poll() and wait() wait for at least one condition to be met.
Again, what a system call that waits for many conditions to be met at >>>>> once can be useful for?
select?
I took Pavel to mean 'wait for all conditions to be true' rather than
'wait for one or more conditions to be true'.
Ahhh. I missed that. Sorry everybody! ;^o
at once" that Bonita missed on Linux for some reason I still cannot get
or relate to.
Am 19.11.2023 um 21:08 schrieb Chris M. Thomasson:
I suspect that you are unfamiliar with how WaitForMultipleObjects
works... ...
Absolutely not, but with WFMO you'd need a lot of semaphores or events whereas my solution needs one semaphore and you'd be limited to MAXIMUM _WAIT_OBJECTS == 64 threads which can join the barrier.
And why do you think I didn't know that ? I've shown that I used that
with my monitor and you even didn't have to look at the source since
I've explained that I'm using WFMO multiple times.
Did you read that article on MSDN as well? Iirc, its around 20 years old.
On 2023-11-18, Scott Lurndal <scott@slp53.sl.home> wrote:
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> writes:
Bonita Montero wrote:
Am 18.11.2023 um 03:16 schrieb Pavel:what does it have to do with what I wrote?
There is no system call in UNIX to wait for many conditions to
be met at once; but I do not see why it would be useful.
poll() and wait() wait for at least one condition to be met.
Again, what a system call that waits for many conditions to be met
at once can be useful for?
Rendezvous.
e.g. pthread_barrier_wait.
Also this:
while (!this_condition() && !that_condition() &&
!other_condition()) pthread_cond_wait(&cond, &mutex);
One condition variable can be used to wait for any subset of the
actual conditions over the shared variables protected by the mutex.
When I switched to a Win32 development job in the mid 1990's, it
amused me that Win32 had all these stupid things like
WaitForMultipleObjects (with a weird 64 limit), instead of just
providing condition variables.
Today, Microsoft provides condition variables.
Modules of a large program should use callbacks to notify that
something is ready. That's the most flexible API. The caller can
build proper asynchronous control flows around that, or bind the
callback to some signaling object according to how they see fit.
Say I have a module that works with three other modules that can spontaneously make some condition ready. If they all provide a
callback, I can set a flag in the callback and broadcast or signal a condition variable. Then I can have threads wait for all three
things to be ready, or any one of the three things.
Am 20.11.2023 um 21:18 schrieb Chris M. Thomasson:
Did you read that article on MSDN as well? Iirc, its around 20 years old.
Has WFMO ever changed ?
On Sat, 18 Nov 2023 20:29:51 -0000 (UTC)
Kaz Kylheku <864-117-4973@kylheku.com> wrote:
On 2023-11-18, Scott Lurndal <scott@slp53.sl.home> wrote:
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> writes:
Bonita Montero wrote:
Am 18.11.2023 um 03:16 schrieb Pavel:what does it have to do with what I wrote?
There is no system call in UNIX to wait for many conditions to
be met at once; but I do not see why it would be useful.
poll() and wait() wait for at least one condition to be met.
Again, what a system call that waits for many conditions to be met
at once can be useful for?
Rendezvous.
e.g. pthread_barrier_wait.
Also this:
while (!this_condition() && !that_condition() &&
!other_condition()) pthread_cond_wait(&cond, &mutex);
One condition variable can be used to wait for any subset of the
actual conditions over the shared variables protected by the mutex.
When I switched to a Win32 development job in the mid 1990's, it
amused me that Win32 had all these stupid things like
WaitForMultipleObjects (with a weird 64 limit), instead of just
providing condition variables.
1. WaitForMultipleObjects() can wait on any mix of objects
2. More importantly, it can wait on wake up events originated both
inside the process and outside.
Today, Microsoft provides condition variables.
Which, I would guess, never used by 99.9% of programs that were not
ported to Windows from some other platform.
Modules of a large program should use callbacks to notify that
something is ready. That's the most flexible API. The caller can
build proper asynchronous control flows around that, or bind the
callback to some signaling object according to how they see fit.
Say I have a module that works with three other modules that can
spontaneously make some condition ready. If they all provide a
callback, I can set a flag in the callback and broadcast or signal a
condition variable. Then I can have threads wait for all three
things to be ready, or any one of the three things.
No, I don't think so.. The interesting aspect was about trying to avoid starvation the the wait array wrt the IOCP vs Event contest. So, we were advised to randomize and/or shift the positions wrt the event side wrt
WFMO.
On 11/23/2023 3:14 PM, Michael S wrote:
Which, I would guess, never used by 99.9% of programs that were not
ported to Windows from some other platform.
Fwiw, check this out:
https://sourceware.org/pthreads-win32/
Am 24.11.2023 um 06:38 schrieb Chris M. Thomasson:
No, I don't think so.. The interesting aspect was about trying to
avoid starvation the the wait array wrt the IOCP vs Event contest. So,
we were advised to randomize and/or shift the positions wrt the event
side wrt WFMO.
You officially can't wait for an IOCP handle with WFMO, although this actually works with my Windows 11 computer. MS should document that and
make a statement since which Windows version this actually works. This
isn't a strong requirement but it would be nice to wait for IOCPs with
WFMO in some cases.
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
On 11/23/2023 3:14 PM, Michael S wrote:
Which, I would guess, never used by 99.9% of programs that were not
ported to Windows from some other platform.
Fwiw, check this out:
https://sourceware.org/pthreads-win32/
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
That's an unnecessary discussion for a C++ programmer since the RAII-ish mutexes and condition variables since C++11 are more convenient to use.
Have you ever wrapped up a C API in C++ using RAII before?
On 11/23/2023 11:59 PM, Bonita Montero wrote:
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
On 11/23/2023 3:14 PM, Michael S wrote:
Which, I would guess, never used by 99.9% of programs that were not
ported to Windows from some other platform.
Fwiw, check this out:
https://sourceware.org/pthreads-win32/
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
That's an unnecessary discussion for a C++ programmer since the RAII-ish
mutexes and condition variables since C++11 are more convenient to use.
Have you ever wrapped up a C API in C++ using RAII before?
On 11/23/2023 11:56 PM, Bonita Montero wrote:
Am 24.11.2023 um 06:38 schrieb Chris M. Thomasson:
No, I don't think so.. The interesting aspect was about trying to
avoid starvation the the wait array wrt the IOCP vs Event contest.
So, we were advised to randomize and/or shift the positions wrt the
event side wrt WFMO.
You officially can't wait for an IOCP handle with WFMO, although this
actually works with my Windows 11 computer. MS should document that and
make a statement since which Windows version this actually works. This
isn't a strong requirement but it would be nice to wait for IOCPs with
WFMO in some cases.
Humm... You should be using:
https://learn.microsoft.com/en-us/windows/win32/fileio/getqueuedcompletionstatusex-func
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 11/23/2023 11:59 PM, Bonita Montero wrote:
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
On 11/23/2023 3:14 PM, Michael S wrote:
Which, I would guess, never used by 99.9% of programs that were not
ported to Windows from some other platform.
Fwiw, check this out:
https://sourceware.org/pthreads-win32/
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
That's an unnecessary discussion for a C++ programmer since the RAII-ish >>> mutexes and condition variables since C++11 are more convenient to use.
Have you ever wrapped up a C API in C++ using RAII before?
I generally consider using RAII for synchronization primitives
to be counterindicated. Amongst the reasons:
1) The critical sections usually end up being far to large
2) It makes reasoning about the synchronization code and
potential nested locking more difficult.
On 2023-11-24, Scott Lurndal <scott@slp53.sl.home> wrote:
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 11/23/2023 11:59 PM, Bonita Montero wrote:
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
On 11/23/2023 3:14 PM, Michael S wrote:
Which, I would guess, never used by 99.9% of programs that were not >>>>>> ported to Windows from some other platform.
Fwiw, check this out:
https://sourceware.org/pthreads-win32/
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
That's an unnecessary discussion for a C++ programmer since the RAII-ish >>>> mutexes and condition variables since C++11 are more convenient to use. >>>>
Have you ever wrapped up a C API in C++ using RAII before?
I generally consider using RAII for synchronization primitives
to be counterindicated. Amongst the reasons:
1) The critical sections usually end up being far to large
Use braces?
{
mutex_locker m(obj);
}
2) It makes reasoning about the synchronization code and
potential nested locking more difficult.
It's just a syntactic sugar to avoid forgetting to unlock.
The thing is, you need a complementary unlocker to
avoid the nesting:
{
mutex_locker m(obj);
// ...
if (obj.situation()) {
mutex_unlocker u(obj); // temporarily give up mutex
other_obj.method(); // this can call us back again
}
}
Am 24.11.2023 um 10:22 schrieb Chris M. Thomasson:
On 11/23/2023 11:56 PM, Bonita Montero wrote:
Am 24.11.2023 um 06:38 schrieb Chris M. Thomasson:
No, I don't think so.. The interesting aspect was about trying to
avoid starvation the the wait array wrt the IOCP vs Event contest.
So, we were advised to randomize and/or shift the positions wrt the
event side wrt WFMO.
You officially can't wait for an IOCP handle with WFMO, although this
actually works with my Windows 11 computer. MS should document that and
make a statement since which Windows version this actually works. This
isn't a strong requirement but it would be nice to wait for IOCPs with
WFMO in some cases.
Humm... You should be using:
https://learn.microsoft.com/en-us/windows/win32/fileio/getqueuedcompletionstatusex-func
Why do you think I don't know GetQueuedCompletionStatus() ?
I said that it would be nice to do a WFMO on a IOCP in addition to that.
On 11/24/2023 10:33 AM, Kaz Kylheku wrote:
On 2023-11-24, Scott Lurndal <scott@slp53.sl.home> wrote:
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 11/23/2023 11:59 PM, Bonita Montero wrote:
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
On 11/23/2023 3:14 PM, Michael S wrote:
Which, I would guess, never used by 99.9% of programs that were not >>>>>>> ported to Windows from some other platform.
Fwiw, check this out:
https://sourceware.org/pthreads-win32/
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
That's an unnecessary discussion for a C++ programmer since the RAII-ish >>>>> mutexes and condition variables since C++11 are more convenient to use. >>>>>
Have you ever wrapped up a C API in C++ using RAII before?
I generally consider using RAII for synchronization primitives
to be counterindicated. Amongst the reasons:
1) The critical sections usually end up being far to large
Use braces?
{
mutex_locker m(obj);
}
DING!!! :^)
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 11/24/2023 10:33 AM, Kaz Kylheku wrote:
On 2023-11-24, Scott Lurndal <scott@slp53.sl.home> wrote:
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 11/23/2023 11:59 PM, Bonita Montero wrote:
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
On 11/23/2023 3:14 PM, Michael S wrote:
Which, I would guess, never used by 99.9% of programs that were not >>>>>>>> ported to Windows from some other platform.
Fwiw, check this out:
https://sourceware.org/pthreads-win32/
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
That's an unnecessary discussion for a C++ programmer since the RAII-ish >>>>>> mutexes and condition variables since C++11 are more convenient to use. >>>>>>
Have you ever wrapped up a C API in C++ using RAII before?
I generally consider using RAII for synchronization primitives
to be counterindicated. Amongst the reasons:
1) The critical sections usually end up being far to large
Use braces?
{
mutex_locker m(obj);
}
DING!!! :^)
No, not really. It's not always that
easy, and sometimes programmers even use 'goto'.
That's certainly no more readable than
pthread_lock(obj);
do something
pthread_unlock(obj);
I'd argue the RAII solution is less readable.
How would that even work? You do not need to create an event per
connection in IOCP model. IOCP is a different model that is not
compatible with WFMO.
It's just a syntactic sugar to avoid forgetting to unlock ...
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 11/24/2023 10:33 AM, Kaz Kylheku wrote:
On 2023-11-24, Scott Lurndal <scott@slp53.sl.home> wrote:
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 11/23/2023 11:59 PM, Bonita Montero wrote:
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
On 11/23/2023 3:14 PM, Michael S wrote:
Which, I would guess, never used by 99.9% of programs that were not >>>>>>>> ported to Windows from some other platform.
Fwiw, check this out:
https://sourceware.org/pthreads-win32/
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
That's an unnecessary discussion for a C++ programmer since the RAII-ish >>>>>> mutexes and condition variables since C++11 are more convenient to use. >>>>>>
Have you ever wrapped up a C API in C++ using RAII before?
I generally consider using RAII for synchronization primitives
to be counterindicated. Amongst the reasons:
1) The critical sections usually end up being far to large
Use braces?
{
mutex_locker m(obj);
}
DING!!! :^)
No, not really. It's not always that
easy, and sometimes programmers even use 'goto'.
That's certainly no more readable than
pthread_lock(obj);
do something
pthread_unlock(obj);
I'd argue the RAII solution is less readable.
On 2023-11-24, Scott Lurndal <scott@slp53.sl.home> wrote:
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 11/23/2023 11:59 PM, Bonita Montero wrote:
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
On 11/23/2023 3:14 PM, Michael S wrote:
Which, I would guess, never used by 99.9% of programs that were not >>>>>> ported to Windows from some other platform.
Fwiw, check this out:
https://sourceware.org/pthreads-win32/
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
That's an unnecessary discussion for a C++ programmer since the RAII-ish >>>> mutexes and condition variables since C++11 are more convenient to use. >>>>
Have you ever wrapped up a C API in C++ using RAII before?
I generally consider using RAII for synchronization primitives
to be counterindicated. Amongst the reasons:
1) The critical sections usually end up being far to large
Use braces?
{
mutex_locker m(obj);
}
2) It makes reasoning about the synchronization code and
potential nested locking more difficult.
It's just a syntactic sugar to avoid forgetting to unlock.
The thing is, you need a complementary unlocker to
avoid the nesting:
{
mutex_locker m(obj);
// ...
if (obj.situation()) {
mutex_unlocker u(obj); // temporarily give up mutex
other_obj.method(); // this can call us back again
}
}
Am 25.11.2023 um 18:28 schrieb Scott Lurndal:
I've used both, but in code (bare metal os/hv) compiled with
-fno-exceptions the following is preferable to RAII.
pthread_lock(obj);
if (xxx) goto unlock;
do something
if (yyy) goto unlock;
do something else
unlock:
pthread_unlock(obj);
Why do you disable exceptions with code that doesn't throw ?
I've used both, but in code (bare metal os/hv) compiled with
-fno-exceptions the following is preferable to RAII.
pthread_lock(obj);
if (xxx) goto unlock;
do something
if (yyy) goto unlock;
do something else
unlock:
pthread_unlock(obj);
Am 24.11.2023 um 19:33 schrieb Kaz Kylheku:
It's just a syntactic sugar to avoid forgetting to unlock ...
RAII is magnitudes more convenient and lass error-prone
than manual resource handling.
Op 25.nov.2023 om 01:08 schreef Scott Lurndal:
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 11/24/2023 10:33 AM, Kaz Kylheku wrote:
On 2023-11-24, Scott Lurndal <scott@slp53.sl.home> wrote:
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 11/23/2023 11:59 PM, Bonita Montero wrote:
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
On 11/23/2023 3:14 PM, Michael S wrote:
Which, I would guess, never used by 99.9% of programs that were not >>>>>>>>> ported to Windows from some other platform.
Fwiw, check this out:
https://sourceware.org/pthreads-win32/
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
That's an unnecessary discussion for a C++ programmer since the RAII-ish
mutexes and condition variables since C++11 are more convenient to use. >>>>>>>
Have you ever wrapped up a C API in C++ using RAII before?
I generally consider using RAII for synchronization primitives
to be counterindicated. Amongst the reasons:
1) The critical sections usually end up being far to large
Use braces?
{
mutex_locker m(obj);
}
DING!!! :^)
No, not really. It's not always that
easy, and sometimes programmers even use 'goto'.
That's certainly no more readable than
pthread_lock(obj);
do something
pthread_unlock(obj);
I'd argue the RAII solution is less readable.
In many cases it is not that simple.
It is more like:
{
mutex_locker m(obj);
do something
if (....) continue;
if (....) break;
if (...) return;
do something else
}
vs.:
pthread_lock(obj);
{
do something
if (...) {
pthread_unlock(obj);
continue;
}
if (...) {
pthread_unlock(obj);
break;
}
if (....) {
pthread_unlock(obj);
return;
}
do something else
} catch (...) {
pthread_unlock(obj);
throw;
}
pthread_unlock(obj);
Personally I find the first way more readable and easier to maintain.
On 2023-11-25, Bonita Montero <Bonita.Montero@gmail.com> wrote:
Am 24.11.2023 um 19:33 schrieb Kaz Kylheku:
It's just a syntactic sugar to avoid forgetting to unlock ...
RAII is magnitudes more convenient and lass error-prone
than manual resource handling.
Sure, but that's not necessarily an effective way to "sell" it to
someone who is being skeptical.
Kaz Kylheku <864-117-4973@kylheku.com> writes:
On 2023-11-25, Bonita Montero <Bonita.Montero@gmail.com> wrote:
Am 24.11.2023 um 19:33 schrieb Kaz Kylheku:
It's just a syntactic sugar to avoid forgetting to unlock ...
RAII is magnitudes more convenient and lass error-prone
than manual resource handling.
Sure, but that's not necessarily an effective way to "sell" it to
someone who is being skeptical.
I would argue that is is not 'less error-prone' than
explicit locking, properly written and unit tested.
On 11/24/2023 4:08 PM, Scott Lurndal wrote:^^^^^^^^^^^^^
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 11/24/2023 10:33 AM, Kaz Kylheku wrote:
On 2023-11-24, Scott Lurndal <scott@slp53.sl.home> wrote:
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 11/23/2023 11:59 PM, Bonita Montero wrote:
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
On 11/23/2023 3:14 PM, Michael S wrote:
Which, I would guess, never used by 99.9% of programs that were >>>>>>>>> not
ported to Windows from some other platform.
Fwiw, check this out:
https://sourceware.org/pthreads-win32/
Am 24.11.2023 um 06:35 schrieb Chris M. Thomasson:
That's an unnecessary discussion for a C++ programmer since the
RAII-ish
mutexes and condition variables since C++11 are more convenient
to use.
Have you ever wrapped up a C API in C++ using RAII before?
I generally consider using RAII for synchronization primitives
to be counterindicated. Amongst the reasons:
1) The critical sections usually end up being far to large
Use braces?
{
mutex_locker m(obj);
}
DING!!! :^)
No, not really. It's not always that
easy, and sometimes programmers even use 'goto'.
That's certainly no more readable than
pthread_lock(obj);
do something
pthread_unlock(obj);
I'd argue the RAII solution is less readable.
RAII can come in handy. I don't think its all that bad. Humm... _______________________
{
mutex_raii_lock(my_lock);
}
_______________________
vs:
_______________________
my_lock.lock();
my_lock.unlock();
_______________________
Btw, wrt C++, RAII tends to work rather well with exceptions... ;^)
Am 25.11.2023 um 00:43 schrieb Chris M. Thomasson:
How would that even work? You do not need to create an event per
connection in IOCP model. IOCP is a different model that is not
compatible with WFMO.
You'd have to ask GQCS after you waited.
Actually WFMO works
on a IOCP für my Windows 11 PC, but this isn't documented.
Kaz Kylheku <864-117-4973@kylheku.com> writes:
On 2023-11-25, Bonita Montero <Bonita.Montero@gmail.com> wrote:
Am 24.11.2023 um 19:33 schrieb Kaz Kylheku:
It's just a syntactic sugar to avoid forgetting to unlock ...
RAII is magnitudes more convenient and lass error-prone
than manual resource handling.
Sure, but that's not necessarily an effective way to "sell" it to
someone who is being skeptical.
I would argue that is is not 'less error-prone' than
explicit locking, properly written and unit tested.
On Sat, 25 Nov 2023 19:30:03 GMT
scott@slp53.sl.home (Scott Lurndal) wrote:
Kaz Kylheku <864-117-4973@kylheku.com> writes:
On 2023-11-25, Bonita Montero <Bonita.Montero@gmail.com> wrote:
Am 24.11.2023 um 19:33 schrieb Kaz Kylheku:
It's just a syntactic sugar to avoid forgetting to unlock ...
RAII is magnitudes more convenient and lass error-prone
than manual resource handling.
Sure, but that's not necessarily an effective way to "sell" it to
someone who is being skeptical.
I would argue that is is not 'less error-prone' than
explicit locking, properly written and unit tested.
RAII is horrible, but unfortunately necessary in big undisciplined C++ projects.
The root bug in C++ language design are constructors that can fail, but
can't return error code.
That problem begot exceptions. And the presence of exceptions begot
RAII. RAII is bad, but less bad than other solutions.
Huh? Drill down on that. What do you mean wrt "_after_ you waited"?
So your hack can break at any time? ...
So your hack can break at any time? Keep in mind that I said GQCSEX...
:^) Its more efficient that GQCS. ...
On Sat, 25 Nov 2023 19:30:03 GMT
scott@slp53.sl.home (Scott Lurndal) wrote:
Kaz Kylheku <864-117-4973@kylheku.com> writes:
On 2023-11-25, Bonita Montero <Bonita.Montero@gmail.com> wrote:
Am 24.11.2023 um 19:33 schrieb Kaz Kylheku:
It's just a syntactic sugar to avoid forgetting to unlock ...
RAII is magnitudes more convenient and lass error-prone
than manual resource handling.
Sure, but that's not necessarily an effective way to "sell" it to
someone who is being skeptical.
I would argue that is is not 'less error-prone' than
explicit locking, properly written and unit tested.
RAII is horrible, but unfortunately necessary in big undisciplined C++ projects.
The root bug in C++ language design are constructors that can fail, but
can't return error code.
That problem begot exceptions. And the presence of exceptions begot
RAII. RAII is bad, but less bad than other solutions.
Once you stop thinking that code can fail, and write code that doesn't
fail, it all becomes much easier, and RAII is just another useful tool.
(And you can compile with exceptions fully disabled.)
Am 26.11.2023 um 13:54 schrieb David Brown:
Once you stop thinking that code can fail, and write code that doesn't
fail, it all becomes much easier, and RAII is just another useful
tool. (And you can compile with exceptions fully disabled.)
With exceptions and RAII failures are also very easy to handle because
you handle them only at a few places and not where they happen or in
the call levels between.
Avoiding exceptions looks hard to me because the runtime can throw a
lot of exceptions, mostly bad_alloc()s or system_error()s.
No, exceptions do not make things easier - they make them /different/.
Sometimes it might be helpful to move failure handling to a different
part of the code, sometimes it makes things harder.
Any code that sees a "bad_alloc" exception is already borked.
It is not failing because of the exception, it is failing because
of the bad programming.
Am 26.11.2023 um 16:28 schrieb David Brown:
No, exceptions do not make things easier - they make them /different/.
Without exceptions you'd have to deal with return codes at each call
level; this *is* much more work.
Sometimes it might be helpful to move failure handling to a different
part of the code, sometimes it makes things harder.
In C++ exceptions are mostly used for resource collapse situations, i.e.
out of memory errors, network errors of filesystem failures.
With that
exceptions are the most convenient way to handle that. These types of
errors are handled in most cases.
Any code that sees a "bad_alloc" exception is already borked.
With exceptions you can handle such situations in a clean way with
a small effort.
It is not failing because of the exception, it is failing because
of the bad programming.
bad_alloc doesn't depend on the programming but rather how much memory
you have. You might ignore bad_alloc for small allocations since they're unlikely to happen, but not for large allocations.
I don't understand your attitude while programming with C++ because the runtime uses exceptions so much.
Am 26.11.2023 um 13:54 schrieb David Brown:
Once you stop thinking that code can fail, and write code that doesn't
fail, it all becomes much easier, and RAII is just another useful tool.
(And you can compile with exceptions fully disabled.)
With exceptions and RAII failures are also very easy to handle because
you handle them only at a few places and not where they happen or in
the call levels between.
Avoiding exceptions looks hard to me because the runtime can throw a
lot of exceptions, mostly bad_alloc()s or system_error()s.
On 26/11/2023 18:51, Bonita Montero wrote:
Am 26.11.2023 um 16:28 schrieb David Brown:
No, exceptions do not make things easier - they make them /different/.
Without exceptions you'd have to deal with return codes at each call
level; this *is* much more work.
As I said, anyone who claims their preference is always right, is wrong.
Sometimes it might be helpful to move failure handling to a different
part of the code, sometimes it makes things harder.
In C++ exceptions are mostly used for resource collapse situations, i.e.
out of memory errors, network errors of filesystem failures.
These are completely different situations. /Sometimes/ exceptions are a convenient way to handle network or filesystem issues. They are never a good way of handling out of memory errors, because out of memory errors
are caused by failures of the code, not external causes.
With that
exceptions are the most convenient way to handle that. These types of
errors are handled in most cases.
Back here in the real world, most exceptions are /not/ handled -
programmers implementing the lower level functions think that exceptions
are someone else's problem and pass the buck up the line. Programmers implementing the higher level parts don't know that the lower level
parts might through an exception - they assume functions do what they
claim to do.
Used properly, exceptions can be helpful in some situations.
Unfortunately they are rarely used properly.
Any code that sees a "bad_alloc" exception is already borked.
With exceptions you can handle such situations in a clean way with
a small effort.
No, you can't. You cannot magically make more memory appear, nor
magically fix the crappy code that caused a memory error in the first place. You are blindly buying into the myth.
It is not failing because of the exception, it is failing because
of the bad programming.
bad_alloc doesn't depend on the programming but rather how much memory
you have. You might ignore bad_alloc for small allocations since they're
unlikely to happen, but not for large allocations.
If you are trying to make an allocation that is too big for the system,
you are doing things wrong. Throwing an exception does not help,
because catching the exception cannot help.
I don't understand your attitude while programming with C++ because the
runtime uses exceptions so much.
The C++ code I use never throws exceptions. I never have them enabled.
I don't miss them.
(I don't use C++ for the kinds of uses where exceptions can be helpful.)
On 11/26/2023 11:27 AM, David Brown wrote:
On 26/11/2023 18:51, Bonita Montero wrote:
Am 26.11.2023 um 16:28 schrieb David Brown:
No, exceptions do not make things easier - they make them /different/.
Without exceptions you'd have to deal with return codes at each call
level; this *is* much more work.
As I said, anyone who claims their preference is always right, is wrong.
Sometimes it might be helpful to move failure handling to a
different part of the code, sometimes it makes things harder.
In C++ exceptions are mostly used for resource collapse situations, i.e. >>> out of memory errors, network errors of filesystem failures.
These are completely different situations. /Sometimes/ exceptions are
a convenient way to handle network or filesystem issues. They are
never a good way of handling out of memory errors, because out of
memory errors are caused by failures of the code, not external causes.
Yup. One time I was experimenting with ways to allow a proxy server I
was coding up to die before exhausting non-paged memory by artificially limiting the memory. This limit was used to make it go into a panic mode
even though it has exhausted all of the non-paged memory. It just got
too close. Iiic, it worked fairly well.
A panic mode would make the server drop all "stale", timedout, ect, connections. It would also try to reclaim as much memory and resources
as it could, without cancelling currently active and working connections...
Basically, where you say:
________
They are never a good way of handling out of memory errors
________
Is true.
With that
exceptions are the most convenient way to handle that. These types of
errors are handled in most cases.
Back here in the real world, most exceptions are /not/ handled -
programmers implementing the lower level functions think that
exceptions are someone else's problem and pass the buck up the line.
Programmers implementing the higher level parts don't know that the
lower level parts might through an exception - they assume functions
do what they claim to do.
Used properly, exceptions can be helpful in some situations.
Unfortunately they are rarely used properly.
Any code that sees a "bad_alloc" exception is already borked.
With exceptions you can handle such situations in a clean way with
a small effort.
No, you can't. You cannot magically make more memory appear, nor
magically fix the crappy code that caused a memory error in the first
place. You are blindly buying into the myth.
It is not failing because of the exception, it is failing because
of the bad programming.
bad_alloc doesn't depend on the programming but rather how much memory
you have. You might ignore bad_alloc for small allocations since they're >>> unlikely to happen, but not for large allocations.
If you are trying to make an allocation that is too big for the
system, you are doing things wrong. Throwing an exception does not
help, because catching the exception cannot help.
I don't understand your attitude while programming with C++ because the
runtime uses exceptions so much.
The C++ code I use never throws exceptions. I never have them
enabled. I don't miss them.
(I don't use C++ for the kinds of uses where exceptions can be helpful.)
Am 26.11.2023 um 00:06 schrieb Chris M. Thomasson:
Huh? Drill down on that. What do you mean wrt "_after_ you waited"?
If you want to wait mor than on the IOCP itself you could use WFMO
and if the IOCP was signalled GQCS afterwards. With an IOCP you can
wait only for the IOCP and maybe an alert if you use GQCSE.
So your hack can break at any time? ...
It would be nice if MS would document since when this works.
So your hack can break at any time? Keep in mind that I said GQCSEX...
:^) Its more efficient that GQCS. ...
It's not about the efficiency but that you could be signalled other
waitable kernel objects also.
On 11/26/2023 2:35 AM, Bonita Montero wrote:
Am 26.11.2023 um 00:06 schrieb Chris M. Thomasson:
Huh? Drill down on that. What do you mean wrt "_after_ you waited"?
If you want to wait mor than on the IOCP itself you could use WFMO
and if the IOCP was signalled GQCS afterwards. With an IOCP you can
wait only for the IOCP and maybe an alert if you use GQCSE.
Huh? This does not make sense to me at all. Have you ever used GQCS or
GQCSEX at all? Humm...
So your hack can break at any time? ...
It would be nice if MS would document since when this works.
LOL! You are a character.
So your hack can break at any time? Keep in mind that I said
GQCSEX... :^) Its more efficient that GQCS. ...
It's not about the efficiency but that you could be signalled other
waitable kernel objects also.
Huh?
They are never a good way of handling out of memory errors, because
out of memory errors are caused by failures of the code, not external causes.
Back here in the real world, most exceptions are /not/ handled - ...
No, you can't. You cannot magically make more memory appear, ...
If you are trying to make an allocation that is too big for the system,
you are doing things wrong. ...
The C++ code I use never throws exceptions. ...
Am 27.11.2023 um 00:45 schrieb Chris M. Thomasson:
On 11/26/2023 2:35 AM, Bonita Montero wrote:
Am 26.11.2023 um 00:06 schrieb Chris M. Thomasson:
Huh? Drill down on that. What do you mean wrt "_after_ you waited"?
If you want to wait mor than on the IOCP itself you could use WFMO
and if the IOCP was signalled GQCS afterwards. With an IOCP you can
wait only for the IOCP and maybe an alert if you use GQCSE.
Huh? This does not make sense to me at all. Have you ever used GQCS or
GQCSEX at all? Humm...
Idiot ...
So your hack can break at any time? ...
It would be nice if MS would document since when this works.
LOL! You are a character.
So your hack can break at any time? Keep in mind that I said
GQCSEX... :^) Its more efficient that GQCS. ...
It's not about the efficiency but that you could be signalled other
waitable kernel objects also.
Huh?
On 11/26/2023 8:24 PM, Bonita Montero wrote:
Am 27.11.2023 um 00:45 schrieb Chris M. Thomasson:
On 11/26/2023 2:35 AM, Bonita Montero wrote:
Am 26.11.2023 um 00:06 schrieb Chris M. Thomasson:
Huh? Drill down on that. What do you mean wrt "_after_ you waited"?
If you want to wait mor than on the IOCP itself you could use WFMO
and if the IOCP was signalled GQCS afterwards. With an IOCP you can
wait only for the IOCP and maybe an alert if you use GQCSE.
Huh? This does not make sense to me at all. Have you ever used GQCS
or GQCSEX at all? Humm...
Idiot ...
You are the one that wants to pass a IOCP handle to WFMO, idoit!
I still don't think you know how GQCS and/or GQCSEX works.
On 11/26/2023 11:57 PM, Bonita Montero wrote:
I told you twice that this would make sense if you additionally would
wait for some other waitable kernel objects. If the IOCP is signalled
you'd do an additional GQCS() on the IOCP. This actually works with
Windows 11 and it would be nice if MS would document since which Win-
dows version it is safe to have a WFMO() on a IOCP.
This is undocumented behavior, and I am not sure what benefit it would
have anyway. ...
https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitformultipleobjects
________________
When bWaitAll is TRUE, the function's wait operation is completed only
when the states of all objects have been set to signaled. The function
does not modify the states of the specified objects until the states of
all objects have been set to signaled. For example, a mutex can be
signaled, but the thread does not get ownership until the states of the
other objects are also set to signaled. In the meantime, some other
thread may get ownership of the mutex, thereby setting its state to nonsignaled.
________________
Am 27.11.2023 um 07:22 schrieb Chris M. Thomasson:
On 11/26/2023 8:24 PM, Bonita Montero wrote:
Am 27.11.2023 um 00:45 schrieb Chris M. Thomasson:
On 11/26/2023 2:35 AM, Bonita Montero wrote:
Am 26.11.2023 um 00:06 schrieb Chris M. Thomasson:
Huh? Drill down on that. What do you mean wrt "_after_ you waited"? >>>>>If you want to wait mor than on the IOCP itself you could use WFMO
and if the IOCP was signalled GQCS afterwards. With an IOCP you can
wait only for the IOCP and maybe an alert if you use GQCSE.
Huh? This does not make sense to me at all. Have you ever used GQCS
or GQCSEX at all? Humm...
Idiot ...
You are the one that wants to pass a IOCP handle to WFMO, idoit!
I told you twice that this would make sense if you additionally would
wait for some other waitable kernel objects. If the IOCP is signalled
you'd do an additional GQCS() on the IOCP. This actually works with
Windows 11 and it would be nice if MS would document since which Win-
dows version it is safe to have a WFMO() on a IOCP.
I still don't think you know how GQCS and/or GQCSEX works.
You don't understand what I write.
Am 26.11.2023 um 20:27 schrieb David Brown:
They are never a good way of handling out of memory errors, because
out of memory errors are caused by failures of the code, not external
causes.
These errors can happen depending on the type of application and
bad_alloc()s are a clean way to handle that. All other ways to
handle that like error codes are less convenient.
Back here in the real world, most exceptions are /not/ handled - ...
You're talking about your applications and you think all peopl
do it like you do.
No, you can't. You cannot magically make more memory appear, ...
No one claims that for exceptions, but you can stop an operation
and recover from that with RAII and exceptions in a clean way.
If you are trying to make an allocation that is too big for the
system, you are doing things wrong. ...
This usually doesn't depend on the application but on the input
of a user.
The C++ code I use never throws exceptions. ...
Then you must have dropped most parts of the standardy library.
Out of memory failures are /never/ clean. A program that tries to get
more memory than is available, using standard allocators, is broken.
I am not saying that the alternative to bad_alloc exceptions is error
codes for memory failures - I am saying that the alternative is not
having memory allocation failures during normal operations.
No, I am talking about reality. /I/ don't use exceptions in C++.
They are not enabled in my builds. How exceptions are handled is
a meaningless question for my own code.
It is extremely difficult to write truly exception-safe code, ...
An application that does not check the input from the user is doing
things wrong.
Of course I have. It is useless for the work I do.
Am 27.11.2023 um 10:38 schrieb David Brown:
Of course I have. It is useless for the work I do.
And you think it's useless for everyone by saying that handling
bad_alloc doesn't usually make sense.
No, I said that most of the standard library is useless for the work
I do, but useful for other people. And I've said that exceptions
can be useful (but not for my work), but are not the kind of wonderful universal "clean" failure handling mechanism you seem to believe.
Am 27.11.2023 um 09:28 schrieb Chris M. Thomasson:[...]
On 11/26/2023 11:57 PM, Bonita Montero wrote:
I told you twice that this would make sense if you additionally would
wait for some other waitable kernel objects. If the IOCP is signalled
you'd do an additional GQCS() on the IOCP. This actually works with
Windows 11 and it would be nice if MS would document since which Win-
dows version it is safe to have a WFMO() on a IOCP.
This is undocumented behavior, and I am not sure what benefit it would
have anyway. ...
If you can imagine the benefit of waiting for multiple kernel objects
you can also imagine the benefit of waiting multiple kernel objects
where at least one object is an IOCP.
On 26/11/2023 00:29, Michael S wrote:
On Sat, 25 Nov 2023 19:30:03 GMT
scott@slp53.sl.home (Scott Lurndal) wrote:
Kaz Kylheku <864-117-4973@kylheku.com> writes:
On 2023-11-25, Bonita Montero <Bonita.Montero@gmail.com> wrote:
Am 24.11.2023 um 19:33 schrieb Kaz Kylheku:
It's just a syntactic sugar to avoid forgetting to unlock ...
RAII is magnitudes more convenient and lass error-prone
than manual resource handling.
Sure, but that's not necessarily an effective way to "sell" it to
someone who is being skeptical.
I would argue that is is not 'less error-prone' than
explicit locking, properly written and unit tested.
RAII is horrible, but unfortunately necessary in big undisciplined C++
projects.
The root bug in C++ language design are constructors that can fail, but
can't return error code.
That's easily solved in cases like this - write constructors that can't
fail.
In the kind of systems I work with, something like acquiring a mutex
cannot fail unless there is a major system failure that renders it
unsafe to run anything - the system then turns off all the machinery it controls, logs everything it can, and alerts the user to the failure.
That applies equally to a free-standing "lock" function or an RAII constructor solution. There is no need for exceptions, error codes, or anything of that sort.
That problem begot exceptions. And the presence of exceptions begot
RAII. RAII is bad, but less bad than other solutions.
I am not a fan of exceptions in low-level code or control code. They
are fine in high-level PC stuff when dealing with things that can
reasonably fail but where you don't want to bother with all the details
all the time - such as a constructor for opening a handle to a database.
(I mostly use Python for that kind of thing anyway, but that's just personal choice.)
Once you stop thinking that code can fail, and write code that doesn't
fail, it all becomes much easier,
and RAII is just another useful tool.
(And you can compile with exceptions fully disabled.)
Am 26.11.2023 um 00:06 schrieb Chris M. Thomasson:
Huh? Drill down on that. What do you mean wrt "_after_ you waited"?
If you want to wait mor than on the IOCP itself you could use WFMO
and if the IOCP was signalled GQCS afterwards. With an IOCP you can
wait only for the IOCP and maybe an alert if you use GQCSE.
So your hack can break at any time? ...
It would be nice if MS would document since when this works.
So your hack can break at any time? Keep in mind that I said GQCSEX...
:^) Its more efficient that GQCS. ...
It's not about the efficiency but that you could be signalled other
waitable kernel objects also.
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 16.11.2023 um 16:02 schrieb Scott Lurndal:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 15.11.2023 um 21:08 schrieb Chris M. Thomasson:
Are you sure its 100% atomic for use in multi-thread sync algorithms? >>>>If MSVC generates that code it's atomic.
No, if Intel architecture documentation specifies that it is
single-copy atomic, then it is single-copy atomic.
MSVC relies for sure on the right behaviour.
Right. Keep thinking that.
MSVC is just a poor-to-middling C compiler.
MSVC has the strongest C++20-conformance but the weakest optimizer.
Faint praise, indeed. Nobody other than Herb cares about C++20 conformance.
Most real world C++ code relies on C++11 for portability. Most
of our systems and our customers systems don't even support C++17.
On 11/26/2023 4:54 AM, David Brown wrote:
Once you stop thinking that code can fail, and write code that doesn't
fail, it all becomes much easier,
Amen. :^)
and RAII is just another useful tool. (And you can compile with
exceptions fully disabled.)
On 11/26/2023 2:35 AM, Bonita Montero wrote:
Am 26.11.2023 um 00:06 schrieb Chris M. Thomasson:
Huh? Drill down on that. What do you mean wrt "_after_ you waited"?
If you want to wait mor than on the IOCP itself you could use WFMO
and if the IOCP was signalled GQCS afterwards. With an IOCP you can
wait only for the IOCP and maybe an alert if you use GQCSE.
So your hack can break at any time? ...
It would be nice if MS would document since when this works.
So your hack can break at any time? Keep in mind that I said
GQCSEX... :^) Its more efficient that GQCS. ...
It's not about the efficiency but that you could be signalled other
waitable kernel objects also.
God knows what WFMO is going to do to that IOCP handle. It could break
things at a lower level of logic.
Kaz Kylheku wrote:
On 2023-11-14, Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo>My point was that the "unblocked" thread could be the thread that "won"
wrote:
"as-if" and "according to the scheduling policy (if applicable)" here
are important. The standard intent may be to permit only the threads
that are "unblocked" contend for the mutex -- as opposed to all
non-blocked threads.
It's possible that only one thread is unblocked by a
pthread_cond_signal. It takes at least two parties to contend for
something.
the contention. "as-if" there meant that the threads didn't really need
to be all woken up / unblocked and start contending; but the contention
could be resolved according to the scheduling policy (the same one that
would be applied if they were actually running and contending for the
mutex, without any waiting for the condvar) within the signal call.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 496 |
Nodes: | 16 (2 / 14) |
Uptime: | 58:38:48 |
Calls: | 9,760 |
Calls today: | 1 |
Files: | 13,742 |
Messages: | 6,185,442 |