2009-05-08 5 views
0

Bon, d'abord un peu d'arrière-plan. Nous avions besoin d'un verrou de lecture/écriture inter-processus. Nous avons décidé d'utiliser un fichier et de verrouiller le premier octet en utilisant LockEx et UnlockEx. La classe crée un fichier dans le dossier temporaire du système lors de sa création. Le fichier est créé avec l'accès readwrite et partage read | write | delete. Nous spécifions également DeleteOnClose afin de ne pas laisser de nombreux fichiers temporaires. Évidemment, AcquireReader et AcquireWriter appellent LockEx avec les options appropriées et les appels ReleaseLock UnlockEx.
Nous avons testé cette classe en utilisant une petite application que vous pouvez exécuter plusieurs fois et cela fonctionne parfaitement. L'application qui l'utilise a un problème, que nous avons réussi à reproduire dans une autre petite application de test. Dans le pseudo code, il estVerrou inter-processeurs Reader Writer (ou poignées de fichiers et accès refusés)

 
Create InterProcessReaderWriter 
Dispose InterProcessReaderWriter without acquiring any locks 
Launch a child process which takes a reader lock 

La première fois que cela fonctionne, cela fonctionne très bien. Si vous tentez de l'exécuter à nouveau, alors que le processus fils de la première fois contient toujours le verrou, nous obtenons une exception UnauthorisedAccessException lorsque vous essayez d'ouvrir le fichier.
Cela semble être un problème d'autorisation, pas une violation de partage, mais tous les processus de ce scénario de test s'exécutent sous le même utilisateur. Quelqu'un a-t-il des idées?

J'ai remarqué l'autre question qui suggère d'utiliser un mutex et un sémaphore pour réaliser ce que nous voulons. Je pourrais changer notre implémentation, mais j'aimerais quand même savoir ce qui cause ce problème.

Répondre

0

Il me semble que le processus enfant tente d'accéder au même fichier deux fois.

sont les noms de fichiers temporaires uniques? Pourquoi ne pas verrouiller tout le fichier?

+0

Nous essayons d'accéder au même fichier. Nous essayons d'implémenter quelque chose de similaire au fonctionnement de l'accès avec son fichier .ldb. Mais seulement un verrou par fichier, dans le cas le premier octet. – pipTheGeek

0

plutôt que le 1er octet. La classe d'exemple ci-dessous présente l'avantage de pouvoir fonctionner sur plusieurs machines sur plusieurs process, plutôt que de la limiter à une seule machine.

Voici un exemple simple utilisant la classe lockfilehelper ci-dessous.

Module Module1 
    Sub Main() 
     Using lockFile As New LockFileHelper("\\sharedfolder\simplefile.lock") 
      If lockFile.LockAcquire(1000) Then 
       ' Do your work here. 
      Else 
       ' Manage timeouts here. 
      End If 
     End Using 
    End Sub 
End Module 

Voici le code de la classe Helper.

Public Class LockFileHelper 
    Implements IDisposable 
    '------------------------------------------------------------------------------------------------- 
    ' We use lock files in various places in the system to provide a simple co-ordination mechanism 
    ' between different threads within a process and for sharing access to resources with the same 
    ' process running across different machines. 
    '------------------------------------------------------------------------------------------------- 
    Private _lockFileName As String 
    Private _ioStream As IO.FileStream 
    Private _acquiredLock As Boolean = False 
    Private _wasLocked As Boolean = False 
    Public Sub New(ByVal LockFileName As String) 
     _lockFileName = LockFileName 
    End Sub 
    Public ReadOnly Property LockFileName() As String 
     Get 
      Return _lockFileName 
     End Get 
    End Property 
    Public ReadOnly Property WasLocked() As Boolean 
     Get 
      Return _wasLocked 
     End Get 
    End Property 
    Public Function Exists() As Boolean 
     Return IO.File.Exists(_lockFileName) 
    End Function 
    Public Function IsLocked() As Boolean 
     '------------------------------------------------------------------------------------------------- 
     ' If this file already locked? 
     '------------------------------------------------------------------------------------------------- 
     Dim Result As Boolean = False 
     Try 
      _ioStream = IO.File.Open(_lockFileName, IO.FileMode.Create, IO.FileAccess.ReadWrite, IO.FileShare.None) 
      _ioStream.Close() 
     Catch ex As System.IO.IOException 
      ' File is in used by another process. 
      Result = True 
     Catch ex As Exception 
      Throw ex 
     End Try 

     Return Result 
    End Function 
    Public Sub LockAcquireWithException(ByVal TimeOutMilliseconds As Int32) 
     If Not LockAcquire(TimeOutMilliseconds) Then 
      Throw New Exception("Timed out trying to acquire a lock on the file " & _lockFileName) 
     End If 
    End Sub 
    Public Function LockAcquire(ByVal TimeOutMilliseconds As Int32) As Boolean 
     '------------------------------------------------------------------------------------------------- 
     ' See have we already acquired the lock. THis can be useful in situations where we are passing 
     ' locks around to various processes and each process may want to be sure it has acquired the lock. 
     '------------------------------------------------------------------------------------------------- 
     If _acquiredLock Then 
      Return _acquiredLock 
     End If 

     _wasLocked = False 
     Dim StartTicks As Int32 = System.Environment.TickCount 
     Dim TimedOut As Boolean = False 
     If Not IO.Directory.Exists(IO.Path.GetDirectoryName(_lockFileName)) Then 
      IO.Directory.CreateDirectory(IO.Path.GetDirectoryName(_lockFileName)) 
     End If 
     Do 
      Try 
       _ioStream = IO.File.Open(_lockFileName, IO.FileMode.Create, IO.FileAccess.ReadWrite, IO.FileShare.None) 
       _acquiredLock = True 
      Catch ex As System.IO.IOException 
       ' File is in used by another process. 
       _wasLocked = True 
       Threading.Thread.Sleep(100) 
      Catch ex As Exception 
       Throw ex 
      End Try 
      TimedOut = ((System.Environment.TickCount - StartTicks) >= TimeOutMilliseconds) 
     Loop Until _acquiredLock OrElse TimedOut 
     '------------------------------------------------------------------------------------------------- 
     ' Return back the status of the lock acquisition. 
     '------------------------------------------------------------------------------------------------- 
     Return _acquiredLock 
    End Function 
    Public Sub LockRelease() 
     '------------------------------------------------------------------------------------------------- 
     ' Release the lock (if we got it in the first place) 
     '------------------------------------------------------------------------------------------------- 
     If _acquiredLock Then 
      _acquiredLock = False 
      If Not IsNothing(_ioStream) Then 
       _ioStream.Close() 
       _ioStream = Nothing 
      End If 
     End If 
    End Sub 
    Private disposedValue As Boolean = False  ' To detect redundant calls 
    ' IDisposable 
    Protected Overridable Sub Dispose(ByVal disposing As Boolean) 
     If Not Me.disposedValue Then 
      If disposing Then 
       Call LockRelease() 
      End If 

      ' TODO: free shared unmanaged resources 
     End If 
     Me.disposedValue = True 
    End Sub 
#Region " IDisposable Support " 
    ' This code added by Visual Basic to correctly implement the disposable pattern. 
    Public Sub Dispose() Implements IDisposable.Dispose 
     ' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above. 
     Dispose(True) 
     GC.SuppressFinalize(Me) 
    End Sub 
#End Region 
End Class 
+0

À l'origine, nous avions choisi de verrouiller une plage dans le fichier car cela nous permettait d'utiliser DeleteOnClose. Je ne sais pas comment cela fonctionnerait quand vous devez fermer le fichier afin de changer le niveau de verrouillage. – pipTheGeek

Questions connexes