T.R | Title | User | Personal Name | Date | Lines |
---|
1518.1 | Related to 1404? | HYDRA::BRYANT | | Wed Apr 09 1997 09:28 | 2 |
| The scenario described in 1404 looks similiar to what Software.com is
experiencing. It's not clear if a fix for this has been approved though?
|
1518.2 | When does fs get destroyed? | WIBBIN::NOYCE | Pulling weeds, pickin' stones | Wed Apr 09 1997 09:36 | 21 |
| > void * producer(void * data)
> {
> int n;
> for (n = 0; n < 10000; n++) {
> // printf("%d --->\n", n);
> FakeSema fs;
> put(&buffer, n, &fs);
> fs.acquire();
> }
> return NULL;
> }
Each time you execute this loop body, you create a new
FakeSema object, pass its address to put(), perform an
acquire() operation on it ... and then destroy it.
I assume you wanted these FakeSema objects to last a little
longer than that!
You should probably use a pointer in this routine, and
explicitly allocate the FakeSema's with new(). Then explicitly
delete them in your consumer function.
|
1518.3 | | DCETHD::BUTENHOF | Dave Butenhof, DECthreads | Wed Apr 09 1997 11:19 | 21 |
| It would certainly be more efficient to reuse the fs object on subsequent
iterations. However, it's only there to synchronize with the completion of
the consumer's matching get (or, more accurately, the consumer's
fp->release() call. So (aside from performance issues) it's fine to destroy
it after the fs.acquire() returns. Still, it'd be a heck of a lot more
efficient for each producer to create ONE FakeSema, and use it for each
buffer it queues.
And, yes, this does look like a possible symptom of the 1404 problem. The fix
will (finally!) go out in PTmin (4.0D). Pete's also talked about trying to
put it into the support streams for earlier versions -- but whether he'll be
successful probably depends on exactly why it didn't get into 4.0A or 4.0B.
(It may be that Jaki didn't push hard enough at the time, or that there were
political situations that have changed since the initial attempt.)
I built & ran the program on my workstation (essentially 4.0D-6) against our
latest sources, and it ran fine. (By the way, in a 2 minute run with 100
threads, substantially shorter than the program's default 1000 seconds, the
test created and destroyed about a million mutexes and condition variables.)
/dave
|
1518.4 | My friends at Software.com want to know... | HYDRA::BRYANT | | Wed Apr 09 1997 15:32 | 7 |
| Can you describe what the bug is?
How can they work around it until a patch becomes available - by ignoring the
status from pthread_mutex_destroy()?
Thanks.
Pat Bryant
|
1518.5 | | DCETHD::BUTENHOF | Dave Butenhof, DECthreads | Wed Apr 09 1997 16:40 | 27 |
| 1404 describes the problem (particularly 1404.2). There was a race in unlock,
where the mutex was unlocked (but internally "referenced", which prevents
destruction) before the unlocking thread looked for waiters to unblock.
Another thread could grab and release the lock, and try to delete it, during
that time. (This is an "unlikely" race on a uniprocessor, but not
impossible.) The code was a convenient, if slightly "loose" interpretation of
the original standard -- it was made illegal along the way by some subtle
changes of which I missed the full significance until someone ran into the
problem, and I eventually had to admit what they were doing was, in fact,
allowed by the standard (deleting after an unlock while other threads are
still "referencing" the mutex).
1404.6 suggests a possible workaround. And, yes, you could also ignore the
destroy -- but that is a resource leak. If you do it too often (and as we've
pointed out, you do it A LOT -- like millions of times), you'll build up a
lot of undestroyed mutexes.
In your case, the best workaround would be to avoid destroying the FakeSema
until the producer is finished. That eliminates the race between the consumer
and producer and substantially improves performance by eliminating all of
those calls to init and destroy the mutexes and condition variables. Sounds
like "win, win" to me. Unless, of course, the REAL application can't
practically be made to do that. In that case, you've got the other
workarounds (either waiting for the destroy to succeed, or letting the
mutexes build up).
/dave
|
1518.6 | | SPECXN::DERAMO | Dan D'Eramo | Wed Apr 09 1997 21:24 | 28 |
| How does the program behave after making the changes suggested
in reply .2?
Dan
void * producer(void * data)
{
int n;
for (n = 0; n < 10000; n++) {
// printf("%d --->\n", n);
FakeSema *fp = new FakeSema;
put(&buffer, n, fp);
fp->acquire();
}
return NULL;
}
void * consumer(void * data)
{
int d;
while (1) {
FakeSema *fp;
d = get(&buffer, fp);
fp->release();
// printf("---> %d\n", d);
delete fp;
}
}
|
1518.7 | | DCETHD::BUTENHOF | Dave Butenhof, DECthreads | Thu Apr 10 1997 07:56 | 26 |
| But that still runs through millions of new/create/destroy/delete cycles.
Much better would be something like this:
void * producer(void * data)
{
int n;
FakeSema *fp = new FakeSema;
for (n = 0; n < 10000; n++) {
// printf("%d --->\n", n);
put(&buffer, n, fp);
fp->acquire();
}
delete fp;
return NULL;
}
void * consumer(void * data)
{
int d;
while (1) {
FakeSema *fp;
d = get(&buffer, fp);
fp->release();
// printf("---> %d\n", d);
}
}
|
1518.8 | Create the semaphore outside the loop, as in .7 | WIBBIN::NOYCE | Pulling weeds, pickin' stones | Thu Apr 10 1997 09:03 | 10 |
| Re .6
I was confused. I didn't realize that producer() creates the
semaphore, then waits for consumer to eat the value before
producer [destroys the semaphore and] goes around its loop again.
In .2 I thought there was a bug in the program, but there isn't
-- the only problem is the number of mutex_destroy operations.
Dave's version in .7 is the best answer to that, for this
example program. Each producer creates one long-lived semaphore,
and it gets serially reused for each data value that producer
puts into the buffer. Can the real software do something similar?
|
1518.9 | | SPECXN::DERAMO | Dan D'Eramo | Thu Apr 10 1997 12:37 | 8 |
| >I didn't realize that producer() creates the
>semaphore, then waits for consumer to eat the value before
^^^^^^^^^^^^^^^^^^
It does? Oh ... that's what acquire / release do.
Okay, never mind. :-)
Dan
|