- Thread-safe initialization of static objects - 6 Updates
"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:
Post a Comment