Re: IPC resource access counting problem
On Nov 9, 7:03 am, Joseph M. Newcomer <newco...@flounder.com> wrote:
We needed it to allow us to free up resources in a shared data segment.
joe
On Thu, 8 Nov 2007 09:48:32 -0800, "David Ching" <d...@remove-this.dcsoft.com> wrote:
"Joseph M. Newcomer" <newco...@flounder.com> wrote in message
news:ja66j3lsc2s6612a1ufplhot70qpbcsrqm@4ax.com...
The problem here is that if program A is open and increments (and you MUST
use
InterlockedIncrement to increment the value, not ++!), program B opens and
increments, and
A crashes, then the file will not be deleted because A has not had a
chance to decrement.
It also only works if both instances are running on the same machine.
It doesn't surprise me that MS-DOS versions of pretend-Windows are full of
bugs. But it
helps if you are specific about which platform you are using, since most
of us treat these
kludges as dead products and ignore them.
One way I handled this was to have an array (fixed-size) of process IDs.
The array was
protected by a mutex. When a process starts up, it locks the table and
adds its process
ID to the array (for my purposes, I set the limit to 100, although we
never expected more
than 3 or 4 instances to run). When a process terminated, it did the
following:
Lock the table
remove its process ID and decrement count
if count== 0 take final cleanup action, we're done
if count > 0
for each element,
check if the process exists
SendMessageTimeout query
if failure, remove element from table and decrement count
if count == 0, take final cleanup action, we're done
The idea is that if a process of the same ID exists, there is a high
probability it is the
process that modified the program. However, because process IDs can be
recycled if a
prorcess terminates, I would call SendMessageTimeout to query the other
process with a
user-defined message. If I got a confirmation (the return value was the
user-defined
message ID...you can't use 0 or 1 because some processes written by MS
return 1 for
messages they don't understand...) then it was still my program; if I got
any other value
or a timeout (pick a short timeout like 50ms, I knew I'd never tie up the
message pump
that long...) I could decrement the count. We never had a problem again.
joe
That is a very robust way of solving the problem.
-- David
Joseph M. Newcomer [MVP]
email: newco...@flounder.com
Web:http://www.flounder.com
MVP Tips:http://www.flounder.com/mvp_tips.htm- Hide quoted text -
- Show quoted text -
Finally got around to looking at this again. Noone's probably
listening anymore but I thought I'd post what I did anyway. I realised
you can get access to the counter in a CSemaphore because the Unlock
method returns it (although what it was before the unlock). So I
created this class to invert the logic a bit of how the CSemaphore was
meant to work...
class FileDeleter
{
#define ZERO_BASE 10000 //max file opens before a wait happens
private:
CSemaphore* semaphore;
public:
CString filename;
FileDeleter(CString fName) : filename(fName)
{
fName.Replace("\\","_");
semaphore=new CSemaphore(ZERO_BASE,ZERO_BASE,fName);
semaphore->Lock();
}
~FileDeleter()
{
LONG cnt;
semaphore->Unlock(1,&cnt);
if (cnt==ZERO_BASE-1)
{
DeleteFile((LPCTSTR)filename);
}
delete semaphore;
}
};
It could have been a lot cleaner if it wasn't for the need to get rid
of "\\" from a filename so I could use it as a semaphore name. Each
construction decrements the counter, each destruction increments it.
When it gets back to where it started I can delete the file.
BTW DeleteFile is documented as dodgy: My docs say...
Windows 95: The DeleteFile function deletes a file even if it is open
for normal I/O or as a memory-mapped file. To prevent loss of data,
close files before attempting to delete them.
Later docs include Windows 98 and Me as suffering the same problem.