Thursday, September 7, 2023

Digest for comp.lang.c++@googlegroups.com - 6 updates in 1 topic

"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Sep 07 12:41PM -0700

On 9/7/2023 12:27 PM, Bonita Montero wrote:
 
>> No. A simple hash of a pointer into an index works out okay, not
>> too  slow at all. Fwiw, check this out, tell me what you think.
 
> Then the number of mutexes would be fixed.
 
Yup. It uses address based hashing into the fixed mutex table. It can be
used to simulate atomics when:
 
https://en.cppreference.com/w/cpp/atomic/atomic/is_lock_free
 
is false.
Richard Damon <Richard@Damon-Family.org>: Sep 07 12:52PM -0700

On 9/7/23 12:20 PM, Chris M. Thomasson wrote:
> constructor would create a thread that would in turn call into a virtual
> function and start using the object before its constructor was
> completed. A massive race condition, nasty ones!
 
Yes, such a thread needs to understand that the system isn't fully
configured. And yes, a base class creating a thread needs that thread to
understand that the object isn't fully created yet and do something to
handle that issue (which likely requires some help from the most derived
class).
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Sep 07 12:58PM -0700

On 9/7/2023 12:52 PM, Richard Damon wrote:
> understand that the object isn't fully created yet and do something to
> handle that issue (which likely requires some help from the most derived
> class).
 
I actually got to a point where I said no creating threads in
constructors! I have seen to many problems. Create the object _first_,
then expose it to a thread, or create a thread that works with the
_fully_ constructed object. The types of race conditions I have had to
deal with wrt objects creating threads in constructors have tended to be
rather nasty in nature...
Bonita Montero <Bonita.Montero@gmail.com>: Sep 07 10:00PM +0200

Am 07.09.2023 um 21:41 schrieb Chris M. Thomasson:
 
> Yup. It uses address based hashing into the fixed mutex table.
 
I guess that's not used at all in the runtimes.
Richard Damon <Richard@Damon-Family.org>: Sep 07 01:31PM -0700

On 9/7/23 12:58 PM, Chris M. Thomasson wrote:
> _fully_ constructed object. The types of race conditions I have had to
> deal with wrt objects creating threads in constructors have tended to be
> rather nasty in nature...
 
I have ONE class that does this, but it is for a somewhat specific
embedded environment with deterministic scheduling and just a single
core, so the thread is created with a lower priority then the creator so
it can't start running until the creator blocks, which it isn't allowed
to do until the constructor finishes. It also is normally used early in
the program before the "OS" is turned on, so the created thread can't
actually run until the OS is turned on.
 
But, for the more general case where you can't control that, (under more
"normal" conditions on the typical "powerful" computer), yes, that would
be a risky thing to be doing.
scott@slp53.sl.home (Scott Lurndal): Sep 07 09:13PM

>_fully_ constructed object. The types of race conditions I have had to
>deal with wrt objects creating threads in constructors have tended to be
>rather nasty in nature...
 
The race condition is pretty easy to resolve. Turn thread initialization
into a two-phase operation.
 
When we have an object that requires its own thread, it will inherit
from a base class called c_thread. The constructor for c_thread will
create the thread which eventually executes the objects 'run' function. The
pthread_create call starts the thread executing at the static function
c_thread::run(void *obj), where the argument is a pointer to the object
itself.
 
That static function sets the process name (prctl(PR_SET_NAME)) and
then waits on a pthread_cond_t (thread_initialized) declared as a data member of
c_thread.
 
Meanwhile, the derived object constructor runs in the original thread after the c_thread
constructor returns and initializes the object. Once the object is fully
initialized (which may happen in the constructor, or may happen
at some later point in time during program startup), the c_thread::run
method condition variable (thread_initialized) is signaled and the
static ::run function transfers control to the derived class virtual ::run
function.
 
/**
* Static pthread start function. Invokes thread specific run virtual
* function.
*
* @param arg The class object pointer passed in from the pthread_create.
*/
void *
c_thread::run(void *arg)
{
c_thread *tp = (c_thread *)arg;
int diag;
 
pthread_mutex_lock(&tp->t_threadlock);
while (!tp->t_thread_initialized) {
pthread_cond_wait(&tp->t_ready, &tp->t_threadlock);
}
pthread_mutex_unlock(&tp->t_threadlock);
 
diag = prctl(PR_SET_NAME, tp->t_thread_name, NULL, NULL, NULL, NULL);
if (diag == -1) {
tp->t_logger->log("Unable to set thread name: %s\n", strerror(errno));
}
 
tp->t_running = true;
tp->run();
tp->t_running = false;
 
return NULL;
}
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: