Mutex/Lock

C

Chris Forone

hello group,

is there a chance for other functions to get the lock if i have
following loop:

while (running)
{
Lock local(mutex);
}

if not, is it enough to change scope:

while (running)
{
{
Lock local(mutex);
}
}

thanx & hand, chris
 
G

Gianni Mariani

Chris said:
hello group,

is there a chance for other functions to get the lock if i have
following loop:

while (running)
{
Lock local(mutex);
}

yes - that code is the same as

while (running) {
mutex.lock();
mutex.unlock();
}
if not, is it enough to change scope:

while (running)
{
{
Lock local(mutex);
}
}

Makes no difference.
 
P

Paul Brettschneider

Chris said:
hello group,

is there a chance for other functions to get the lock if i have
following loop:

while (running)
{
Lock local(mutex);
}

if not, is it enough to change scope:

while (running)
{
{
Lock local(mutex);
}
}

You probably want:

{
Lock local(mutex);
while(running)
{
...
}
}
 
C

Chris Forone

Paul said:
You probably want:

{
Lock local(mutex);
while(running)
{
...
}
}

No, the first version is the one i need. its to suspend/resume in a well
defined position in code. So i had:

bool Resume()
{
Lock local(mutex);
// resume thread
}

bool Suspend()
{
Lock local(mutex);
// suspend thread
}

bool Exit()
{
Lock local(mutex);
// here was my dl, because of wait for thread termination :)
}

void Proc()
{
while (active)
{
Lock local(mutex);
// do things
}
}

now my Exit looks:

bool Exit()
{
mutex.Acquire();

if (active)
{
active = false, mutex.Release();
// wait for thread termination :)))
}

mutex.Release();
}

it functs, hope it is waterproof...

thanks & hand, chris

ps: Ideas for better doing it are very welcome!
 
C

Chris Forone

Errata:

bool Exit()
{
mutex.Acquire();

if (active)
{
active = false;
mutex.Release();
// wait for thread termination :)))
}

mutex.Release();
}

if i write:

active = false, mutex.Release()

i think, the mutex is first released -> error

is this right?

thanx & hand, chris
 
P

Paul Brettschneider

Chris said:
No, the first version is the one i need. its to suspend/resume in a well
defined position in code. So i had:

Ah. I misread your question. I think what you want is a notify/signal
mechanism, which should be implemented for every thread package. (In
pthreads it's the pthread_cond_* functions.)
 
J

James Kanze

bool Exit()
{
mutex.Acquire();
if (active)
{
active = false;
mutex.Release();
// wait for thread termination :)))
}

if i write:
active = false, mutex.Release()
i think, the mutex is first released -> error
is this right?

No. There's a sequence point at the comma, so all side effects
of the preceding expression must be finished before any side
effects of the following occur.

I do wonder about your code, however. You really need to
recover the mutex before the end of the if---otherwise, you'll
release it twice. And how do you wait for thread termination:
with a join, or with some sort of global thread counter? In the
latter case, you'll need the mutex to read it as well.

I generally use something like:

void
requestTermination()
{
ScopedLock lock( terminateFlagMutex ) ;
terminateRequested = true ;
}

void
waitForAllThreadsToTerminate()
{
ScopedLock lock( threadCountMutex ) ;
while ( threadCount != 0 ) {
threadCountCondition.wait( lock ) ;
}
}

void
terminate()
{
requestTermination() ;
waitForAllThreadsToTerminate() ;
}

with:

void
endOfThread()
{
ScopedLock lock( threadCountMutex ) ;
-- threadCount ;
threadCountCondition.notify() ;
}

at the end of each thread. (Note that this does require some
care when starting threads, since a race condition can occur
there if you're not careful. In my case, it's not a problem,
because all of the threads are always started by the main
thread, which is also the only thread which will call
terminate(), but if other running threads might start a thread
while you're calling terminate, you'll have to add some
additional logic in thread start-up to avoid the race.)
 
C

Chris Forone

James said:
No. There's a sequence point at the comma, so all side effects
of the preceding expression must be finished before any side
effects of the following occur.

I do wonder about your code, however. You really need to
recover the mutex before the end of the if---otherwise, you'll
release it twice. And how do you wait for thread termination:
with a join, or with some sort of global thread counter? In the
latter case, you'll need the mutex to read it as well.


Thanx for the example. The wait is done with the win32 function
WaitForSingleObject() with no timeout. Excuse me for the incomplete example:

bool Exit()
{
mutex.Acquire();

if (active)
{
active = false;
mutex.Release();

return WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0;
}

mutex.Release();
}

The sideeffect-thing i dont understand...

What about:

return someVar1 == 10 &&
someVar2 != 20 &&
(someVar3 = someFunc()) == true;

and

return (someVar1 == 10) &&
(someVar2 != 20) &&
(someVar3 = someFunc()) == true;

thanx & hand, chris
 
J

jason.cipriani

No, the first version is the one i need. its to suspend/resume in a well
defined position in code. So i had:

bool Resume()
bool Suspend()
bool Exit()
void Proc()
bool Exit()
{
mutex.Acquire();

if (active)
{
active = false, mutex.Release();
// wait for thread termination :)))
}

mutex.Release();

}
ps: Ideas for better doing it are very welcome!


Chris,

It's funny I just implemented almost exactly the same thing. A thread
with Start, Stop, Suspend, and Resume, although in my case I implement
"Start" and "Resume" with the same function. I have been having good
results with this. I use two mutices; one for the thread handles
themselves, and another for the "suspend" flag. You may find this
unnecessary, but in my actual application the "suspend" flag mutex
protects many other things (it is a media playback application of
sorts that maintains a number of other timing related parameters as
well). Note that this isn't real C++:

====================

// threadmtx has default spin count of 0, suspendmtx set at 3000.
CRITICAL_SECTION threadmtx, suspendmtx;
HANDLE hthread = NULL;
bool paused = false;
bool quitflag = false;

Start () {

// Resume thread if it's suspended.
Lock suspendmtx;
paused = false;
Unlock suspendmtx;

// Start thread if it's not running.
Lock threadmtx;
if (hthread == NULL) {
quitflag = false;
hthread = CreateThread(..., Proc, ...);
}
Unlock threadmtx;

}

Suspend () {

// Pause thread.
Lock suspendmtx;
paused = true;
Unlock suspendmtx;

}

Stop () {

// stop thread if it's running
Lock threadmtx;
if (hthread != NULL) {
quitflag = true;
if (WaitForSingleObject(hthread, timeout) == WAIT_TIMEOUT)
TerminateThread(hthread); // sholdn't happen
CloseHandle(hthread);
hthread = NULL;
}
Unlock threadmtx;

}

Proc () {

bool ispaused = false, pausing, unpausing;

// loop until asked to quit
while (!quitflag) {

Lock suspendmtx;
pausing = paused && !ispaused;
unpausing = ispaused && !paused;
ispaused = paused;
Unlock suspendmtx;

if (pausing) {
// do anything you want to do when thread transitions to paused
} else if (unpausing) {
// do anything you want to do when thread transitions to
unpaused
}

if (paused) {
Sleep(10); // or whatever
continue;
}

do normal processing here;

}

}

==== END EXAMPLE ====

Again, apologies for the strange looking example, I pieced it together
in this email from a slightly more complex piece of code. The pausing/
unpausing logic isn't necessary for anything but it lets you do things
when the thread state changes, if you want, I thought I'd throw that
in there. Hopefully it makes sense.

In my case I made a slight trade-off of added code simplicity at the
expense of niceness. The "if (paused) { Sleep(10); continue; }" is the
culprit there. You may instead want to do something like "if (paused)
{ WaitForSingleObject(unpausedevent); }" and SetEvent(unpausedevent)
when you unpause the thread, that way it will sleep until you resume
it rather than looping and waiting.

You could also use SuspendThread/ResumeThread, depending on your
requirements. However, I am not sure where those functions actually
suspend the thread -- I don't know if Windows has a concept of
"suspend points" or if it just stops the thread right where it is in a
potentially unsafe place (for example, in the middle of a critical
section, or in the middle of sending data to an external hardware
device or whatever it is your thread does).

Jason
 
J

James Kanze

James Kanze schrieb:

[...]
Thanx for the example. The wait is done with the win32 function
WaitForSingleObject() with no timeout.

That is, I think, a join.

Windows is noted for using non-standard terminology, although in
this case, it might be justified. Still, if there is a function
which will insist that the handle refers to a thread, and return
an error if it doesn't, I'd use that. Static typing is
significantly more robust than dynamic typing.
Excuse me for the incomplete example:
bool Exit()
{
mutex.Acquire();
if (active)
{
active = false;
mutex.Release();
return WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0;
}
mutex.Release();

This call will fail (probably with an assertion failure, if the
Mutex class is well written) if the condition for the if is
true.
The side effect-thing i dont understand...
What about:
return someVar1 == 10 &&
someVar2 != 20 &&
(someVar3 = someFunc()) == true;

&& and || are also sequence points. But I'd never write code
like that, with a change of state hidden down in the middle of a
complicated expression, where it won't be easily seen. Nor
would I compare with true: if someVar3 has type bool, then
that's what you need, and no comparison is necessary, and if it
doesn't, I'd write the comparison to compare with something of
whatever type it has.
return (someVar1 == 10) &&
(someVar2 != 20) &&
(someVar3 = someFunc()) == true;

Parentheses don't change anything.
 
C

Chris Forone

James said:
James Kanze schrieb:
[...]
Thanx for the example. The wait is done with the win32 function
WaitForSingleObject() with no timeout.

That is, I think, a join.

Windows is noted for using non-standard terminology, although in
this case, it might be justified. Still, if there is a function
which will insist that the handle refers to a thread, and return
an error if it doesn't, I'd use that. Static typing is
significantly more robust than dynamic typing.
Excuse me for the incomplete example:
bool Exit()
{
mutex.Acquire();
if (active)
{
active = false;
mutex.Release();
return WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0;
}
mutex.Release();

This call will fail (probably with an assertion failure, if the
Mutex class is well written) if the condition for the if is
true.
The side effect-thing i dont understand...
What about:
return someVar1 == 10 &&
someVar2 != 20 &&
(someVar3 = someFunc()) == true;

&& and || are also sequence points. But I'd never write code
like that, with a change of state hidden down in the middle of a
complicated expression, where it won't be easily seen. Nor
would I compare with true: if someVar3 has type bool, then
that's what you need, and no comparison is necessary, and if it
doesn't, I'd write the comparison to compare with something of
whatever type it has.
return (someVar1 == 10) &&
(someVar2 != 20) &&
(someVar3 = someFunc()) == true;

Parentheses don't change anything.

--
James Kanze (GABI Software) email:[email protected]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Tanks a lot! Chris
 
C

Chris Forone

It's funny I just implemented almost exactly the same thing. A thread
with Start, Stop, Suspend, and Resume, although in my case I implement
"Start" and "Resume" with the same function. I have been having good
results with this. I use two mutices; one for the thread handles
themselves, and another for the "suspend" flag. You may find this
unnecessary, but in my actual application the "suspend" flag mutex
protects many other things (it is a media playback application of
sorts that maintains a number of other timing related parameters as
well). Note that this isn't real C++:

====================

// threadmtx has default spin count of 0, suspendmtx set at 3000.
CRITICAL_SECTION threadmtx, suspendmtx;
HANDLE hthread = NULL;
bool paused = false;
bool quitflag = false;

Start () {

// Resume thread if it's suspended.
Lock suspendmtx;
paused = false;
Unlock suspendmtx;

// Start thread if it's not running.
Lock threadmtx;
if (hthread == NULL) {
quitflag = false;
hthread = CreateThread(..., Proc, ...);
}
Unlock threadmtx;

}

Suspend () {

// Pause thread.
Lock suspendmtx;
paused = true;
Unlock suspendmtx;

}

Stop () {

// stop thread if it's running
Lock threadmtx;
if (hthread != NULL) {
quitflag = true;
if (WaitForSingleObject(hthread, timeout) == WAIT_TIMEOUT)
TerminateThread(hthread); // sholdn't happen
CloseHandle(hthread);
hthread = NULL;
}
Unlock threadmtx;

}

Proc () {

bool ispaused = false, pausing, unpausing;

// loop until asked to quit
while (!quitflag) {

Lock suspendmtx;
pausing = paused && !ispaused;
unpausing = ispaused && !paused;
ispaused = paused;
Unlock suspendmtx;

if (pausing) {
// do anything you want to do when thread transitions to paused
} else if (unpausing) {
// do anything you want to do when thread transitions to
unpaused
}

if (paused) {
Sleep(10); // or whatever
continue;
}

do normal processing here;

}

}

==== END EXAMPLE ====

Again, apologies for the strange looking example, I pieced it together
in this email from a slightly more complex piece of code. The pausing/
unpausing logic isn't necessary for anything but it lets you do things
when the thread state changes, if you want, I thought I'd throw that
in there. Hopefully it makes sense.

In my case I made a slight trade-off of added code simplicity at the
expense of niceness. The "if (paused) { Sleep(10); continue; }" is the
culprit there. You may instead want to do something like "if (paused)
{ WaitForSingleObject(unpausedevent); }" and SetEvent(unpausedevent)
when you unpause the thread, that way it will sleep until you resume
it rather than looping and waiting.

You could also use SuspendThread/ResumeThread, depending on your
requirements. However, I am not sure where those functions actually
suspend the thread -- I don't know if Windows has a concept of
"suspend points" or if it just stops the thread right where it is in a
potentially unsafe place (for example, in the middle of a critical
section, or in the middle of sending data to an external hardware
device or whatever it is your thread does).

Jason

Thanks for the example. In my case its an "active object" as a timer.
The sync is for a "suspend point" (you said), to Resume/Suspend in a
well defined section. The approach with thread creation at first Start()
i can use eventually, i create the thread in ctor w/ CREATE_SUSPENDED,
saw in the web, create thread in ctor is evil...

Greetings & hand, Chris
 
S

Szabolcs Ferenczi

[...\]> Thanks for the example. In my case its an "active object" as a timer. The
sync is for a "suspend point" (you said), to Resume/Suspend in a well
defined section. The approach with thread creation at first Start() i can
use eventually, i create the thread in ctor w/ CREATE_SUSPENDED, saw in
the web, create thread in ctor is evil...

[...]

Creating threads in a ctor is generally considered evil indeed. However,
starting threads(s) in ctors which act on
___fully___constructed___object(s)___ is NOT! Case in point:

http://groups.google.com/group/comp.lang.c++/msg/20c14991f9e88482

Any thoughts?

As for one remark, you and your enthusiastic friend tried really hard
but finally you could not prove or demonstrate that starting a thread
as the last step in the constructor could result in any problem
provided one is disciplined enough. In fact I have deduced it from the
text of the standard that nothing forbids it.

Second, you yourself solved your own problem or doubt by simply
providing a wrapper template (see your own link).

Third, the concept of _active object_ is a well known concept in
computer science except for in the circles of C++ hackers.

I hope this helps.

Best Regards,
Szabolcs
 
J

James Kanze

bool Exit()
{
mutex.Acquire();
if (active)
{
active = false;
mutex.Release();
// wait for thread termination :)))
}
mutex.Release();

You're still releasing the mutex twice if active is initially
true. Which could cause an assertion failure.
if i write:
active = false, mutex.Release()
i think, the mutex is first released -> error
is this right?

No. Assignment has higher precedence than the comma operator,
so this is the equivalent of:

(active = false), (mutex.Release()) ;

Still, it's something I would avoid at all costs, for reasons of
readability.
 
G

Gianni Mariani

Chris said:
What do you think?

That was posix code. Does Posix have WAIT_ABADONED?

The windows code does not use Win32 (at least the code I wrote).
 
J

Jerry Coffin

[ ... ]
If the threading is implemented as a base class with an abstract
virtual function representing the threads "entry" point, then you simply
cannot create the thread in the constructor. The thread might start running
and call the virtual function before the derived object has even had a
chance to run its ctor; OOPS!

You can _create_ the thread, but you must ensure against it _running_
until the ctor has finished executing. I can't say with certainty that
all environments support creating threads in a suspended state, but some
(e.g. Win32) certainly do.
 
S

Szabolcs Ferenczi

[...]
All you said was that
starting threads in ctors is no big deal if you know what your doing.


Correct. And I still hold that claim. Your friend and you were trying
to contradict that but you failed.
Well,
the OP was on the verge of making a mistake, and I felt the need to put up a
big warning sign. So be it.

You have given a false warning. That is it.
The only point I was trying to make was that you should only start threads
which act on fully constructed objects.

That is a basic misunderstanding on your side. There is no language
rule that would support your claim. In fact, the language rule states
that:

"Member functions, including virtual functions (10.3), can be called
during construction or destruction"

There is no concept of not `fully constructed object' with respect to
calling its own methods. It is allowed to call any method during
construction. On the other hand, the object must be fully constructed
if you are trying to use it from its external environment. This is
what you wrongfully interpret in this case.
Therefore, starting a thread from an
object ctos which is intended to operator on itself is an error.

It is an error according to some C++ hackers only. It is not an error
according to any language rule.
The
active<T> template gets around that limitation by acting as a proxy. It
works very well.

Agreed. So you nicely contradict yourself since you start the thread
in the constructor of the proxy and according to your own reasoning
the object is `not fully constructed' yet. Formally speaking. Or do
you think that in this case you know what you are doing and you can
fake your own principle?
That's not true in all cases.

Do you mean that there are some C++ hackers who are educated enough so
that they are aware of the concept of active objects?

Best Regards,
Szabolcs
 
I

Ian Collins

Szabolcs said:
That is a basic misunderstanding on your side. There is no language
rule that would support your claim. In fact, the language rule states
that:

"Member functions, including virtual functions (10.3), can be called
during construction or destruction"

For the last time: you can only call virtual methods overridden in the
class being constructed or it bases (12.7.3).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,772
Messages
2,569,588
Members
45,100
Latest member
MelodeeFaj
Top