Cross process synchronization of shared resources


A

atlaste

Hi,

I have two different things I'd like to discuss here. Both are about
cross-process synchronization of shared resources. The resources that
are shared are: (1) an object writing to a file and (2) a file. I
threat them as two different problems for various reasons.

The first problem involves the object writing to a file. The problem
might be best explained by thinking of a single log file that's
appended by different programs that interoperate. If we would do
nothing the file would be opened by the programs simultaneously and
written simultaneously, yielding incorrect log entries.

It is my understanding that types from the CLR are not shared and can
thus be used for locking the logging object. So in the logging object
we should be able to handle the condition as follows:

// locks the type of the logging object
lock (typeof(this))
{
// some code to demonstrate the idea...
StreamWriter sw = new StreamWriter(filename, true);
sw.WriteLine("{0}", logline);
sw.Close();
}

Since only this object should be responsible for writing the file,
this should work. If another object locks the file, the type won't be
locked, hence the StreamWriter will throw an exception. If another
program attempts to use the object and write an entry, it will run
into the lock.

I'd like to discuss if this is the/an appropriate way to handle this
problem and why.

The second point of discussion is in locking files between processes.
As far as I know the only way to do this properly is by checking if
the file is available on intervals and if so opening it. Since it is
important to open the file and thereby locking it instantly I believe
the way of doing that properly is wrapping the FileStream as follows:

// -- below is the wrapper class

public class LockingFileStream : IDisposable {
private FileStream fs = null;

public LockingFileStream(string filename) : base()
{
while (fs == null)
{
try
{
fs = File.Open(filename, FileMode.Open, FileAccess.ReadWrite,
FileShare.None);
}
catch (IOException e)
{
System.Threading.Thread.Sleep(1000);
}
}

public FileStream Handle { get { return fs; } }

public void Dispose()
{
// make sure we release the lock here
if (fs != null)
{
fs.Close();
fs.Dispose();
fs = null;
}
}
}

// -- above is the wrapper; here follows a piece of code that uses it

void MyTest()
{
using (LockingFileStream lfs = new LockingFileStream(myFilename))
{
// use lfs.Handle
}
}

// -------

However, this code polls the file to see if it's locked or not. I'd
rather use a monitor or mutex alike construction if that's in any way
possible.

Suggestions?

Cheers,

Stefan de Bruijn
 
Ad

Advertisements

?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

atlaste said:
It is my understanding that types from the CLR are not shared and can
thus be used for locking the logging object.

As the Type object is the same for all instances of an object, it's not
suitable for locking.
So in the logging object
we should be able to handle the condition as follows:

// locks the type of the logging object
lock (typeof(this))

You can't use the typeof keyword on an instance of a class, only on a type.

You should create a private object in the class, that you only use for
synchronising. The reason for this is that it prevents deadlocks, as
code outside the class can not lock on the same object.

Also, as that object is only used for synchronising and nothing else,
the risk is minimal that you should find some reason to expose it
outside the class. If you use some existing object in the class that is
used for something else, like for example filename, in the future you
might want to expose that object outside the class, not realising that
you create a potential for deadlocks.
 
A

atlaste

Dear Göran,

Thanks for the reaction. I think there is still some slight
miscommunication, so I want to point out that this posting is only
about cross-process locking of shared resources (with multiple
programs using the same resource), while I think you reacted on

As the Type object is the same for all instances of an object, it's not
suitable for locking.

This was exactly the point. Since the type is the same for all
instances of the object, between different processes, it is very
suitable for locking between different processes. At the same time
it's very unsuitable for "normal" locking purposes.

Or do I misinterpret your comment?

.... reading it again I start to see your point. I'm locking the object
named "Type" rather than the type itself. Which means my proposed
(first) solution indeed will never work.
You can't use the typeof keyword on an instance of a class, only on a type.

Sorry, I was writing the snippet in the news reader directly :)
You should create a private object in the class, that you only use for
synchronising. The reason for this is that it prevents deadlocks, as
code outside the class can not lock on the same object.

Also, as that object is only used for synchronising and nothing else,
the risk is minimal that you should find some reason to expose it
outside the class. If you use some existing object in the class that is
used for something else, like for example filename, in the future you
might want to expose that object outside the class, not realising that
you create a potential for deadlocks.

That works fine if we're considering a single process / program that
runs multiple threads and uses the object for synchronization. In this
scenario I'm having multiple programs using the same shared DLL for
accessing the resource. As far as I know your solution doesn't work
there, does it?

Cheers,
Stefan de Bruijn.
 
M

Marc Gravell

Since the type is the same for all
instances of the object, between different processes,

As with any .NET object, Type instances do not cross process
boundaries, or even app-domains within a single process.

Equally (as already stated), in many eyes Type shouldn't be used for
locking anyway, since it is very public which can (if another
component is using the same trick) lead to unexpected deadlocks.

For cross-process (or app-domain) sync, either use a file, or
something like a named Mutex / Semaphore etc provided by the OS -
rather than the .NET Monitor ("lock") which is provided by the runtime
and hence is local to your app-domain.

Marc
 
A

atlaste

As with any .NET object, Type instances do not cross process
boundaries, or even app-domains within a single process.

Equally (as already stated), in many eyes Type shouldn't be used for
locking anyway, since it is very public which can (if another
component is using the same trick) lead to unexpected deadlocks.

For cross-process (or app-domain) sync, either use a file, or
something like a named Mutex / Semaphore etc provided by the OS -
rather than the .NET Monitor ("lock") which is provided by the runtime
and hence is local to your app-domain.

Thanks, that answers the first part of my question. I'll dive into the
named mutexes.

About the "file locking" approach I still wonder if there's a way to
lock on a file without a pulling approach (as I described in the first
posting).

Stefan.
 
U

UL-Tomten

this code polls the file to see if it's locked or not. I'd rather
use a monitor or mutex alike construction if that's in any way
possible.

I think it's easy to provoke a race condition in the inner lock if you
poll the file. Perhaps the FileSystemWatcher in cooperation with lock
files (.lock) would work, if you can make the operations sufficiently
atomic?
 
Ad

Advertisements

U

UL-Tomten

I think it's easy to provoke a race condition in the inner lock if you
poll the file. Perhaps the FileSystemWatcher in cooperation with lock
files (.lock) would work, if you can make the operations sufficiently
atomic?

And by "inner lock", for reasons unknown even to myself, I mean "file
lock".
 
Ad

Advertisements

?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

atlaste said:
Dear Göran,

Thanks for the reaction. I think there is still some slight
miscommunication, so I want to point out that this posting is only
about cross-process locking of shared resources (with multiple
programs using the same resource), while I think you reacted on



This was exactly the point. Since the type is the same for all
instances of the object, between different processes, it is very
suitable for locking between different processes. At the same time
it's very unsuitable for "normal" locking purposes.

Or do I misinterpret your comment?

... reading it again I start to see your point. I'm locking the object
named "Type" rather than the type itself. Which means my proposed
(first) solution indeed will never work.

Actually, you are locking neither of those. A lock doesn't protect the
object in any way, the object is only used as an identifier for a mutex
to lock the code block. Another thread can not enter the same code block
at the same time.

However, as you have separate applications, a regular lock/mutex has no
effect at all, as they are local to the application. You have to use a
named mutex for that, as Marc suggested.
Sorry, I was writing the snippet in the news reader directly :)


That works fine if we're considering a single process / program that
runs multiple threads and uses the object for synchronization. In this
scenario I'm having multiple programs using the same shared DLL for
accessing the resource. As far as I know your solution doesn't work
there, does it?

No, it doesn't.

(It does however work for every scenario where the lock keyword is used.)
 

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

Top