Simple question with POSIX

I have this POSIX thread:

void subthread(void)
{
  while(!quit_thread) {

     // do something
     ...

     // don't waste cpu cycles
     if(!quit_thread) usleep(500);
  }

  // free resources
  ...

  // tell main thread we're done
  quit_thread = FALSE;
}

      

Now I want to interrupt subthread () from the main thread. I've tried the following:

quit_thread = TRUE;

// wait until subthread() has cleaned its resources
while(quit_thread);

      

But it won't work! The while () clause never exits, although my subthread explicitly sets quit_thread to FALSE after freeing its resources!

If I change my disconnect code like this:

quit_thread = TRUE;

// wait until subthread() has cleaned its resources
while(quit_thread) usleep(10);

      

Then everything works fine! Can someone explain to me why the first solution does not work and why the version with usleep (10) unexpectedly works? I know this is not a good solution. I could use semaphores / signals for this, but I would like to know something about multithreading, so I would like to know why my first solution does not work.

Thanks!

+2


a source to share


4 answers


Chances are your compiler doesn't know what quit_thread

might be changed by another thread (because C doesn't know about threads, at least at the time this question was asked). Because of this, it optimizes the loop while

for an infinite loop.

In other words, he looks at this code:

quit_thread = TRUE;
while(quit_thread);

      

and thinks to himself, "Ha, nothing in this loop can change quit_thread

to FALSE, so the coder obviously just wanted to write while (TRUE);

."

When you add a call to usleep

, the compiler thinks about it and assumes that the function call can change the global, so it plays safe and doesn't optimize it.

Usually you mark a variable as volatile

to stop the compiler from optimizing it, but in this case, you should use the facilities provided by pthreads and join the thread after setting the flag to true (and not have a feed reset it, do this on the main thread after merging. if necessary). The reason for this is that a connection is likely to be more efficient than a continuous loop waiting for a variable to change, since the thread making the connection will most likely not be executed until the connection is complete.

In your spinning solution, the connecting thread will likely keep running and sucking up the CPU grunt.

In other words, do something like:

Main thread              Child thread
-------------------      -------------------
fStop = false
start Child              Initialise
Do some other stuff      while not fStop:
fStop = true                 Do what you have to do
                         Finish up and exit
join to Child
Do yet more stuff

      




And as an aside, you have to technically protect shared variables with mutexes, but this is one of the few cases where everything is fine, one-way communication, where the semi-mutable values ​​of the variable do not matter (false / not-false).

The reason you usually protect the mutex variable is to stop one thread by seeing it in a half change state. Let's say you have a two byte integer to count some objects and it is set to 0x00ff

(255).

Let us further say that thread A is trying to increase this count, but this is not an atomic operation. It changes the high byte to 0x01

, but before it has a chance to change the low byte to 0x00

, stream B attacks and reads it like 0x01ff

.

Now it's not good if thread B wants to do something with the last item counted by this value. He should look at 0x0100

, but instead try to see 0x01ff

which effect would be wrong, if not catastrophic.

If count was protected by a mutex, thread B will not look at it until thread A has finished updating it, so there will be no problem.

The reason, which doesn't matter in a one-way boolean, is that any half-state will also be considered true or false, so if stream A was halfway between turning 0x0000

in 0x0001

(high byte only), stream B would still see that in as 0x0000

(false) and keep moving (until thread A completes its update next time).

And if thread A turned boolean into 0xffff

, then the half state 0xff00

will still be considered true thread B, so it will complete its task before thread A completes updating the boolean.

Neither of these two possibilities are bad simply because in both threads A is in the process of changing a boolean and will eventually end. Whether stream B detects the tiny bit sooner or a little later is irrelevant.

+1


a source


Without memory fencing , there is no guarantee that values ​​written in one stream will be mapped to another. Most pthread primitives introduce a barrier, as do several system calls such as usleep

. Using a mutex around reads and writes introduces a barrier and generally prevents multibyte values ​​from being visible in a partially written state.



You also need to decouple the idea of ​​asking the thread to stop executing and signaling that it has stopped, and apparently uses the same variable for both.

+2


a source


while(quite_thread);

uses the value quit_thread

set on the line before it. The function call ( usleep

) prompts the compiler to reload the value for each test.

In any case, this is not the correct way to wait for the thread to complete. Use instead pthread_join

.

+1


a source


You are "learning" by mutating the wrong path. The correct way is to learn how to use mutexes and condition variables; any other solution will fail under some circumstances.

+1


a source







All Articles