-
Multiple-readers, single-writer synchronization lock between processes
There's a well-known algorithm that employs readers/writer lock synchronization between threads of a single process on a Windows platform using pure WinAPIs/C++:
http://www.glennslayden.com/code/win...er-writer-lock
In my case I need to do this between several processes, i.e. the writer is in one process, and readers are in other processes. Any idea how to do that?
PS. I need this for an already developed project, so I can't use anything other than C++/MFC or pure WinAPIs. In other words I can't use Boost or the like extensions.
-
Re: Multiple-readers, single-writer synchronization lock between processes
Named mutex of a name in global namespace (single reader/writer access). Or a dedicated read/write broker.
-
Re: Multiple-readers, single-writer synchronization lock between processes
Oh, actually named semaphore could be used for counting readers. And named event to indicate writing in progress.
-
Re: Multiple-readers, single-writer synchronization lock between processes
Quote:
Originally Posted by
Igor Vartanov
Oh, actually named semaphore could be used for counting readers. And named event to indicate writing in progress.
Thanks, Igor. Replacing the critical section with global named mutex should work. The issue is in the counter of readers. I actually thought to use named semaphores for it too, but couldn't come up with a working code. The issue is that semaphores count down and this algorithm needs to count up & down.
So can I ask you to demonstrate what you meant in code?
-
Re: Multiple-readers, single-writer synchronization lock between processes
The idea actually was for reader to inverse the logic behind semaphore object and use ReleaseSemaphore(by 1) to indicate read operation start and WaitForSingleObject to indicate read completion. The semaphore should be created with maximum allowed count but initial count is zero. Of course, reader should catch the mutex and immediately release it after incrementing semaphore. Symmetrically, writer should not grab the mutex until semaphore becomes non-signalled.
One potential danger thing to be confirmed that died reader never blocks the whole mechanism.
-
Re: Multiple-readers, single-writer synchronization lock between processes
Quote:
Originally Posted by
Igor Vartanov
The idea actually was for reader to inverse the logic behind semaphore object and use ReleaseSemaphore(by 1) to indicate read operation start and WaitForSingleObject to indicate read completion. The semaphore should be created with maximum allowed count but initial count is zero. Of course, reader should catch the mutex and immediately release it after incrementing semaphore. Symmetrically, writer should not grab the mutex until semaphore becomes non-signalled.
One potential danger thing to be confirmed that died reader never blocks the whole mechanism.
But how would you know that there're no readers reading the data?
-
Re: Multiple-readers, single-writer synchronization lock between processes
No readers is indicated by semaphore non-signalling state.
-
Re: Multiple-readers, single-writer synchronization lock between processes
Let's put it into code:
Code:
//For simplicity I'm writing it for a single process
class MultiReaderSingleWriter
{
private:
CRITICAL_SECTION m_csWrite;
CRITICAL_SECTION m_csReaderCount;
//long m_cReaders;
HANDLE m_semCounter;
HANDLE m_hevReadersCleared;
public:
MultiReaderSingleWriter()
{
m_semCounter = CreateSemaphore(NULL, 0, 1000, NULL);
InitializeCriticalSection(&m_csWrite);
InitializeCriticalSection(&m_csReaderCount);
m_hevReadersCleared = CreateEvent(NULL,TRUE,TRUE,NULL);
}
~MultiReaderSingleWriter()
{
WaitForSingleObject(m_hevReadersCleared,INFINITE);
CloseHandle(m_semCounter);
CloseHandle(m_hevReadersCleared);
DeleteCriticalSection(&m_csWrite);
DeleteCriticalSection(&m_csReaderCount);
}
void EnterReader(void)
{
EnterCriticalSection(&m_csWrite);
EnterCriticalSection(&m_csReaderCount);
//if (++m_cReaders == 1)
// ResetEvent(m_hevReadersCleared);
ReleaseSemaphore(m_semCounter); //Can we call it here with the count being 0?
//So how do you check the semaphore count here?
LeaveCriticalSection(&m_csReaderCount);
LeaveCriticalSection(&m_csWrite);
}
void LeaveReader(void)
{
EnterCriticalSection(&m_csReaderCount);
//if (--m_cReaders == 0)
// SetEvent(m_hevReadersCleared);
WaitForSingleObject(m_semCounter, 0);
//Same problem here??
LeaveCriticalSection(&m_csReaderCount);
}
void EnterWriter(void)
{
EnterCriticalSection(&m_csWrite);
WaitForSingleObject(m_hevReadersCleared,INFINITE);
}
void LeaveWriter(void)
{
LeaveCriticalSection(&m_csWrite);
}
};
It doesn't seem to work. I don't know that semaphores can be used as counters? I might be wrong. If so, correct me.
-
Re: Multiple-readers, single-writer synchronization lock between processes
The code below is just an idea that needs to be proved, or disproved, or corrected. And no, I never did anything like this before. :)
Code:
#include <windows.h>
#include <crtdbg.h>
class MultiReaderSingleWriter
{
HANDLE m_hSemRead; // counts active readers
HANDLE m_hEvtNoRead; // prevents read operation
public:
MultiReaderSingleWriter()
{
m_hSemRead = CreateSemaphore(NULL, 0, 1000, NULL);
m_hEvtNoRead = CreateEvent(NULL, TRUE, FALSE, NULL);
}
~MultiReaderSingleWriter()
{
CloseHandle(m_hSemRead);
CloseHandle(m_hEvtNoRead);
}
BOOL EnterRead()
{
DWORD waitRes = WaitForSingleObject(m_hEvtNoRead, INFINITE); // blocks until write completion
_ASSERT(WAIT_OBJECT_0 == waitRes);
LONG count = 0;
BOOL res = ReleaseSemaphore(m_hSemRead, 1, &count); // increments semaphore counter
// here you can log count to see internal semaphore counter before you incremented it
_ASSERT(res);
return res;
}
BOOL LeaveRead()
{
DWORD waitRes = WaitForSingleObject(m_hSemRead, 0); // decrement semaphore counter
BOOL res = WAIT_TIMEOUT == waitRes; // here not sure about the exact retcode :)
_ASSERT(res);
return res;
}
BOOL EnterWrite()
{
BOOL res = SetEvent(m_hEvtNoRead); // prevents new reads
_ASSERT(res);
DWORD waitRes = 0;
do
{
// loop until last reader gone
waitRes = WaitForSingleObject(m_hSemRead, 0);
if (WAIT_OBJECT_0 == waitRes)
Sleep(10);
else if (WAIT_TIMEOUT == waitRes)
return TRUE;
else
return FALSE;
} while (TRUE);
return FALSE;
}
BOOL LeaveWrite()
{
BOOL res = ResetEvent(m_hEvtNoRead); // release waiting readers
_ASSERT(res);
return res;
}
};
-
Re: Multiple-readers, single-writer synchronization lock between processes
Thanks, Igor.
Quote:
Code:
DWORD waitRes = WaitForSingleObject(m_hSemRead, 0); // decrement semaphore counter
BOOL res = WAIT_TIMEOUT == waitRes; // here not sure about the exact retcode :)
Yes, I'm not sure about this one either. That's what I meant in my previous post that a semaphore object was never intended as just a counter. Although I do appreciate your "bold" approach to it.
Quote:
One potential danger thing to be confirmed that died reader never blocks the whole mechanism.
Yes, that becomes an issue in case I put your code into several processes. For instance, if one reader crashes and doesn't decrement the semaphore, it will indefinitely deadlock the writer.
Also this, I guess is just nitpicking:
Quote:
Code:
// loop until last reader gone
waitRes = WaitForSingleObject(m_hSemRead, 0);
if (WAIT_OBJECT_0 == waitRes)
Sleep(10);
else if (WAIT_TIMEOUT == waitRes)
return TRUE;
else
return FALSE;
Wouldn't it be better to do:
Code:
waitRes = WaitForSingleObject(m_hSemRead, 10);
and drop Sleep(10); to save those 10ms?
-
1 Attachment(s)
Re: Multiple-readers, single-writer synchronization lock between processes
Actually, the initial code is too dirty. Apparently, 2 AM isn't the best hour for writing clean code. :D
Attached please find the reviewed and debugged variant. (.sln file is not a normal solution but just a debugging session)
The change: writer should release semaphore too, like reader does, otherwise wait distorts the semaphore counter. BTW, this way it peeks into the semaphore counter as well. ;)
Code:
BOOL EnterWrite()
{
PutLog(CString(TEXT("+ ENTER + ")) + TEXT(__FUNCTION__));
BOOL res = ResetEvent(m_hEvtNoRead); // prevents new reads
_ASSERT(res);
DWORD waitRes = 0;
do
{
// loop until last reader gone
LONG count = 0;
res = ReleaseSemaphore(m_hSemRead, 1, &count);
_ASSERT(res);
waitRes = WaitForSingleObject(m_hSemRead, 0);
if (count)
Sleep(10);
else if (WAIT_OBJECT_0 == waitRes)
{
res = TRUE;
break;
}
else
{
res = FALSE;
break;
}
} while (TRUE);
PutLog(CString(TEXT("- RETURN - ")) + CString(__FUNCTION__) + TEXT(", res = ") + ToString(res));
return res;
}
BOOL LeaveWrite()
{
PutLog(CString(TEXT("+ ENTER + ")) + TEXT(__FUNCTION__));
BOOL res = SetEvent(m_hEvtNoRead); // release waiting readers
_ASSERT(res);
PutLog(CString(TEXT("- RETURN - ")) + CString(__FUNCTION__) + TEXT(", res = ") + ToString(res));
return res;
}
-
1 Attachment(s)
Re: Multiple-readers, single-writer synchronization lock between processes
Thanks again. I truly appreciate your unconventional approach to using semaphores.
I reworked your code to use two separate processes (for readers and a writer.) Sorry, I can't write concise solutions like you do, so I opted for a default console app template instead. To test it run the writer first (only one instance is allowed) and then start as many readers as you want. I also removed your log file output and instead redirected it to the screen to achieve faster output (to test synchronization mechanism) and also to give a tester visual clue that threads are running.
I had to remove your CRT I/O file functions in favor of lower-level APIs. Maybe I don't know much about fopen() but it seems to have its own built-in synchronization, which mixed with the results of the synchronization mechanism in this example.
Then, first off, let me correct a bug. When you create m_hEvtNoRead event, it must be set to signaled state. Otherwise the first reader will deadlock without the first writer call.
Then a couple of issues that I ran into (or maybe I should name them as questions):
1. The sleep(10) part of the EnterWrite() method seems to be a bottleneck:
Code:
waitRes = WaitForSingleObject(m_hSemRead, 0);
if (count)
Sleep(10);
but if I rewrite it into:
Code:
waitRes = WaitForSingleObject(m_hSemRead, 10);
if (count)
/*Sleep(10)*/;
it really speeds things up, but unfortunately I get occasional "read fail". Why do you think would that be?
PS. While typing this reply, I let the "writer" run on the background with Sleep(10) line... And it also gave me "read fail" after about 5-10 minutes of continuous running... There still must be an issue somewhere in the this lock... :(
After a quick overview it seems that the part of the code that changes the semaphore count must be enclosed in its own critical section. Don't you think?
2. The second issue is more challenging to fix. As I brought up before, if one of the readers crashes inside its critical section, the writer mechanism will also deadlock. To illustrate, search for the following line in the attached solution, and uncomment it:
Code:
#define INCLUDE_READER_CRASH //Uncommect this line to introduce an artifical "Reader" crash
This will make the reader process crash after 200 reads. When that happens watch the writer ... it will deadlock.
-
1 Attachment(s)
Re: Multiple-readers, single-writer synchronization lock between processes
I think I fixed the issue #1 by enclosing the semaphore in a critical section. Attached is an updated project. There's still the issue #2 remaining though ...
-
Re: Multiple-readers, single-writer synchronization lock between processes
Quote:
unconventional approach to using semaphores
Well, the idea was got from MSDN article after reading about start with zero counter. So it's not that unconventional. :)
Quote:
let me correct a bug. When you create m_hEvtNoRead event, it must be set to signaled state. Otherwise the first reader will deadlock without the first writer call.
It might be a feature, as long as without first write it might be senseless to read the void. You know this better, as I'm totally unaware of your ultimate design.
Quote:
The sleep(10) part of the EnterWrite() method seems to be a bottleneck
I said you before that all my experience with synchronization was mostly about dealing with processes where hundreds of milliseconds never matter. Typically for me in business logic keeping precedence matters much more than super timings. :)
And in case when few milliseconds really is a bottleneck, I'd say that either you need some other synchronization solution, or, which is more probable, your synchronized multi-process reader-writer approach itself is a bottleneck.
Quote:
but unfortunately I get occasional "read fail". Why do you think would that be?
Like any other pure architectural thing it needs to be analyzed for flaws (code review, sequence diagrams, etc.) and properly debugged (by offline logs or interactively). Seems like I just was able to invest an idea, but have no time to purify it, sorry. Maybe other guys here will help. :)
-
Re: Multiple-readers, single-writer synchronization lock between processes
Yes. Thank you. I appreciate it.
-
Re: Multiple-readers, single-writer synchronization lock between processes
I had a thought about the problem of dead reader this morning. Seems like writer should initiate full resync once it was not able to write within some guaranteed interval. Resync results in closing semaphore object and opening a new one with a new name.
This has a few implications. Only writer creates (and possesses) synchronization objects, readers just open those, and close immediately after using. Current valid object names must be published by writer somehow (registry?). Any error case while operating with sync object indicates that reader should reopen the object with the newly published name and repeat the action.
I would say that dedicated data read-write server (multithreaded socket or out-of-proc COM) seems like much more simple and reliable solution. Besides, it will be able to use the original sync class you mentioned in your OP. :)
Or even more radical approach conversion. In your current scheme readers "pull" data. Changing it to "pushing" data (for example, writer posting data over broadcast mailslot and reader listening on the mailslot and caching the last result) may simplify the whole system.
-
Re: Multiple-readers, single-writer synchronization lock between processes
Thanks for sticking with it.
I actually did solve it by abandoning semaphores as counters. I really liked your idea and it worked really great as long as all readers didn't crash within that specific critical section.
What I went with is a shared memory array for the readers count accessible for all readers and a writer. Each consisting of the following elements:
Code:
struct PROC_INFO{
DWORD dwProcID; //Process ID of reader
DWORD dwThreadID; //Thread ID that entered the reader-reading critical section
FILETIME ftCreatedTime; //Time when the process was created to resolve process ID ambiguity in case of a crashed process
};
Then while entering the reader critical section I'd add the calling thread and proc ID into this array and remove it when leaving the critical section. I had to write my own waiting function for the writer though. It'd loop with the Sleep(1) interval and try to open each process by its process ID and if it fails it then removes that element from the shared array. If the count of readers reaches 0 then the writer could begin writing. (Obviously all of these functions with the shared mem must be enclosed it its own mutex controlled critical section.) This approach seems to have eliminated any possible crashes. (Although it requires some additional attention to abandoned mutexes.)
-
Re: Multiple-readers, single-writer synchronization lock between processes
Not sure I understand how this helps when reader dies without cleaning its own record.
-
Re: Multiple-readers, single-writer synchronization lock between processes
Here's a quick pseudo code for the part of the writer's critical section:
Code:
//Making sure that there're no readers reading
WaitForSingleObject(hSharedMemMutex, INFINITE);
for(;WaitForSingleObject(hStopEvent, 1) == WAIT_TIMEOUT;)
{
BOOL bGotLiveReader = FALSE;
PROC_INFO* pPIs = mapped_offset_of_shared_mem_array;
for(int i = 0; i < size_of_shared_mem_array / sizeof(PROC_INFO); i++)
{
if(!pPIs[i].dwProcID)
continue;
HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pPIs[i].dwProcID);
FILETIME ftCreated;
if(GetProcessTimes(hProc, &ftCreated, ...) &&
ftCreated == pPIs[i].ftCreatedTime)
{
bGotLiveReader = TRUE;
break;
}
else
{
pPIs[i].dwProcID = NULL;
}
CloseHandle(hProc);
}
}
if(bGotLiveReader)
break;
}
ReleaseMutex(hSharedMemMutex);
-
Re: Multiple-readers, single-writer synchronization lock between processes
Quote:
Originally Posted by
ahmd
... I had to write my own waiting function for the writer though. It'd loop with the Sleep(1) interval and try to open each process by its process ID and if it fails it then removes that element from the shared array.
You can't write code for inter-process synchronization at the user level. All such code must be at the kernel level which, of course, you have no access to. As such, you must rely on the Windows-provided APIs for synchronization, and work within their premises.
And a call to Sleep will get you laughed out of any serious discussion on synchronization. Get rid of it.
Mike
-
Re: Multiple-readers, single-writer synchronization lock between processes
Mike, I don't want to branch off this discussion into why calling Sleep would be bad ... it's simply a way to relinquish control back to the OS instead of maxing out CPU cycles for unnecessary looping. I can only wish that more developers out there used this approach. Plus, if you look into the code I posted above, the Sleep(1) call is replaced with WaitForSingleObject(hStopEvent, 1), that I agree is a better alternative.
As the kernel synchronization goes, did you see the use of the hSharedMemMutex mutex around the function I posted?
-
Re: Multiple-readers, single-writer synchronization lock between processes
>> it's simply a way to relinquish control back to the OS instead of maxing out CPU cycles for unnecessary looping. I can only wish that more developers out there used this approach.
No. Developers should know that calling Sleep is almost always wrong - seeing it in code is an immediate red flag. In this case, using WaitForSingleObject instead is the right the thing to do. Prefer waiting on something instead of nothing.
Also, you should know that if there are any other open handles to a process, then OpenProcess() will succeed even if it exited an hour ago. In other words, using OpenProcess() on a process that has exited will continue to succeed until all handles to that process have been closed.
What is the resource that is actually being written and read? Shared memory? A file or files?
gg
-
Re: Multiple-readers, single-writer synchronization lock between processes
Quote:
No. Developers should know that calling Sleep is almost always wrong - seeing it in code is an immediate red flag.
I disagree with you. Here's an example. Let's take my code sample above and the three ways to write an outer loop:
1.
Code:
for(;WaitForSingleObject(hStopEvent, 1) == WAIT_TIMEOUT;) //Preferred
2.
Code:
for(;WaitForSingleObject(hStopEvent, 0) == WAIT_TIMEOUT; Sleep(1)) //Almost the same as 1
3.
Code:
for(;WaitForSingleObject(hStopEvent, 0) == WAIT_TIMEOUT;) //BAD!
All three will produce the same outcome. OK, if you go into technicalities, sample 2 will be putting that thread in a non-responsive state for 1 millisecond before checking for a stop event. Will that make a huge difference for an outcome? Yes, if we're dealing with high precision synchronization at stopping that thread. In other cases it is almost identical to sample 1. Sample 3 on the other hand, by not having any artificial delay introduced into it will produce the same outcome but will eat up way more CPU cycles while running, which in turn will translate into wasted energy, i.e. battery life of a device running this software. Many developers don't realize that by "returning CPU back" to the OS they actually let the OS perform all of its necessary power management tasks. (Of course, this greatly depends on the OS too. For instance, something as counter-intuitive as XP or Vista will probably just waste that 1ms, while Windows 7 might "use it wisely", while I'm positive that Windows 8 will "do it right".) This misunderstanding, by the way, is one of the major reasons why most of the legacy Windows software becomes such an energy hog. The point here is that we don't always have a luxury of a delay built into an API (like WaitForSingleObject), so in that case using a short delay like Sleep(1) in a waiting loop is perfectly OK.
So having said that, there's one place where I would not recommend using Sleep, and that is the main GUI thread. In that case relying on a built-in messaging system will be the way to go.
And the last thing I want to say here is that Sleep API seems to have the same kind of infamy as the goto C statement. It's just funny, because both don't compile into anything that you wouldn't get with other waiting APIs or language statements.
Quote:
Also, you should know that if there are any other open handles to a process,
Yes. I'm aware of it. I need to test this scenario and see if an open handle for a "crashed" process will make a difference here.
Quote:
What is the resource that is actually being written and read? Shared memory? A file or files?
In my actual example I need it to synchronize read/write access to system registry, but in the example posted above, it is used to access a file.
-
Re: Multiple-readers, single-writer synchronization lock between processes
You replaced Sleep(1) with WFSO(..., 1). In the circumstances you show here, WFSO with a timeout is no better than Sleep. Both are bad. In fact, anything with (1) or (10) or (pick_any_number_of_msecs) are all equally bad, and you need to learn why if you want to write efficient concurrent code.
There are some situations where Sleep(0) might be acceptable, but there's no point in discussing them at this level.
But it's also true that I could have been less blunt and more helpful.
To answer your original question, to share data between readers and writers (sometimes called producers and consumers), one common approach is a circular buffer, or queue. The approach is favored because there is no need to synchronize access to the buffer itself; it's sufficient to synchronize access only to the put and get pointers to the buffer.
I recognize that your question premised only a single writer, not multiple writers. A single writer might simplify things, but it also might be a red-herring in your quest for a good solution. I say that because if there is only a single writer, then even with a circular buffer designed for multiple writers, there will never be contention for the put pointer.
If you decide on a circular buffer, your design is still not finished. You need to decide on a few more details, such as:
From the perspective of the readers: what happens if there is no data in the buffer? Should the read fail immediately (return false) so as to allow the reading thread to do other work? Or is there no other work for the reading thread, such that the thread should wait in a suspended state and thereafter triggered automatically when more data becomes available in the buffer.
From the perspective of the writer: What happens when the buffer is full? Similar to above should we fail immediately or wait for more room to become available. Or, as another alternative, should we simply over-write data already in the buffer.
From the perspective of both reader and writer: if the answers above involve a wait, then what is the shutdown method? Typically, WFMO with a second mutex is involved.
Mike
-
Re: Multiple-readers, single-writer synchronization lock between processes
>> Prefer waiting on something instead of nothing.
Sleep is waiting on nothing. Waiting on nothing in multi-threaded code is a "red flag" - which in my mind means "we should take a closer look at this code because the author may of only thought they knew what they were doing".
>> on the other hand, by not having any artificial delay introduced into it will produce the same outcome but will eat up way more CPU cycles while running, which in turn will translate into wasted energy, i.e. battery life of a device running this software.
Not exactly the case here, since it's a 1ms busy loop. What is wasteful is the act of polling itself - as apposed to waiting efficiently on a synchronization object - which in turn keeps your thread in a wait state in the kernel until there is work to be done - which in turn allows the CPU to enter a lower power state. Threads that enter a runnable state may also take the CPU out to a higher power state.
None of that really matters in this particular case since if a writer is waiting efficiently, that just means readers are getting their read-on. And if readers are waiting efficiently, then a writer is getting her write-on. :)
Do you really need this complexity just for abandoned readers? Why are readers crashing if all they are doing is reading the registry? :)
What about abandoned writers?
You can build a readers-writer lock with just semaphores, and no polling.
http://en.wikipedia.org/wiki/Readers-writers_problem
The "writers-preference" solution there is fairly straight forward. If you must add abandoned readers logic, I would only have it kick in once a writer finds itself waiting longer than it has to. Reading from the registry should not be time consuming, and since it's a writers-preference algorithm, no writer should have to wait very long.
gg
-
Re: Multiple-readers, single-writer synchronization lock between processes
Quote:
In the circumstances you show here, WFSO with a timeout is no better than Sleep. Both are bad. In fact, anything with (1) or (10) or (pick_any_number_of_msecs) are all equally bad, and you need to learn why if you want to write efficient concurrent code.
Yes, I agree. The reason I need a delay is because of the fact that I need to poll for a condition instead of using a kernel waiting function. And unfortunately there's no built-in kernel waiting function to do what I need in this case.
And speaking of concurrency. I also agree that applying my approach of delaying the polling process for 1 ms is not acceptable for a high-precision concurrency. But, as I explained above, this writer/readers lock is intended for the system registry synchronization. And as we all know, there's nothing slower in the Windows OS than requests to the system registry. So if you plot on the graph the timing for my critical section next to the timing needed to actually write/retrieve data from the system registry, it will be quite minuscule. Thus I chose this approach.
So, yes, the asterisk here is this. If you need it for anything that demands high-precision (say, for a "real-time" I/O), this approach will not work and you'll need to look for something else. Possibly a suggested circular buffer approach...
Quote:
To answer your original question, to share data between readers and writers (sometimes called producers and consumers), one common approach is a circular buffer, or queue.
I considered this approach but decided against it due to one major drawback -- buffer overrun. You also pointed it out yourself. I'll explain the reason why below.
Quote:
Do you really need this complexity just for abandoned readers?
Yes. I also agree that the chance of a reader crashing within a critical section is very slim, but, neglecting this will constitute for me a "sloppy code." So I chose to go a more difficult route.
Yes, absolutely. Igor Vartanov demonstrated above how this could be done. But again, as I already explained, I cannot use a "simpler" code from the Wikipedia page due to the fact that the readers counter should be shared among several processes. And the use of named semaphores, suggested by Igor, has a drawback of locking up a writer in case of a crash within a reader's critical section. Thus, my longer code of manually counting all reader processes + threads from within a writer's critical section.
Quote:
If you must add abandoned readers logic, I would only have it kick in once a writer finds itself waiting longer than it has to.
OK, now we're going back to the same issue as was brought up by MikeAThon with circular buffers and a possible buffer overrun. An obvious question here is, "How big should the buffer be?", or "How long should a writer wait before considering a reader abandoned?" Seems like both have straightforward answers, but they don't. I can't know for sure the answers to either of these questions. A reader might be legitimately locked for a very long time. For instance, a debugging process might lock it up for minutes. Or, an antivirus/firewall process may lock it up virtually indefinitely if it decides to do its own checks. Or, more down-to-earth situation -- when my Windows 7 comes out from a sleep mode something in the file system (on a kernel level) locks it up for a couple of seconds. That delay might be "enormously long" for an average critical section but is perfectly legitimate in this case. Any of these situations will cause either a buffer overrun, or a timer overrun, that will break your proposed writer/readers approaches.
Again, guys, I did my research and I was not able to come up with anything better than the approach I demonstrated above, that doesn't seem to "cut corners." So if you have any solution that is superior to that, I'll be more than willing to learn it?
-
Re: Multiple-readers, single-writer synchronization lock between processes
Are you tryed to use TryEnterCriticalSection unless EnterCriticalSection?
I not read all post of the thread, I not have so time... sorry if this way are explored before...
Best regards.
-
Re: Multiple-readers, single-writer synchronization lock between processes
Quote:
Are you tryed to use TryEnterCriticalSection unless EnterCriticalSection?
I not read all post of the thread, I not have so time...
juanpast, thank you for trying to help. But I suggest that you do read threads before posting. EnterCriticalSection is not the subject of this discussion.