Newsgroup: it.comp.lang.visual-basic
Titolo: File "semaforo"

Salve a tutti,
ho un'applicazione che deve scrivere un file in un percorso.
Un client poi legge questo file, e invia un file con la risposta.
Per evitare che uno leggesse mentre il file era in scrittura da entrambe le
parti ho fatto:
  ff = FreeFile
  Open FileTemp For Output As #ff
  ss = "Domanda"
  Print #ff, ss
  Close ff
 
  FileCopy FileTemp, MioPath & "\Domanda.txt"
  FileCopy FileTemp, MioPath & "\Domanda.lck"
In pratica lavoro sul file, e poi lo copio sia come .txt che come .lck.
Dall'altra parte controllo l'esistenza del file .lck, e se esiste prendo il
.txt.
Il cliente fa la stessa cosa, solo che i file sono Risposta.txt e
Risposta.lck, e sul server controllo sempre il .lck e se presente
acquisisco il .txt
        If Len(Dir$(FileLck)) > 0 Then
          If Len(Dir$(FileTxt)) > 0 Then
	    [Acquisisco dati] 'Molto rapida
            Kill FileLck
          End If
      End If
[rettifica]
In effetti in debug mi ha dato errore proprio sul Kill. Ho anche spostato
il kill dopo il primo IF, ma ha ridato errore.
Probabilmente il fileCopy del file .lck impiega "troppo" tempo e la dir lo
trova prima che esita e sia cancellabile.
Cosa potrei usare? Alla peggio potrei anche tentare di cancellarlo un 2
volte con un intervallo di 200/300msec l'uno dall'altro, non ci dovrebbero
essere problemi dato che i file saranno da 50/100 byte.
Oppure potrei verificare l'esistenza, acquisire, aspettare un pochino e poi
cancellare:
        If Len(Dir$(FileLck)) > 0 Then
          If Len(Dir$(FileTxt)) > 0 Then
	    [Acquisisco dati] 'Molto rapida
            Sleep 500 ms
            Kill FileLck
          End If
      End If
Che mi dite?
Tnx

 Cosa potrei usare? 
Un DoEvents?
Ciao

 Un DoEvents?
Non credo basti, infatti non è il computer stesso che deve aspettare.
Tra l'altro con uno sleep di 200ms ha sempre dato qualche problemino.
Ora ho messo 500ms e sta girando da un pezzo.
Anche se mi fa abbastanza pena come soluzione, metterò comunque un On Error
alla cancellazione del file, tanto per come lavora il programma, mi va bene
anche che lo cancelli al passaggio successivo.

 parti ho fatto:
Scusa la domanda banale, ma la sintassi base di Open, con i relativi
attributi "lock", non andava bene per quello che vuoi fare?
ff = FreeFile
Open FileTemp For Output Lock Read Write As #ff
'ecc...

 Open FileTemp For Output Lock Read Write As #ff
Allora i file vengono scritti ad un evento, ma vengono letti con un timer
di circa 500ms sul server e 2000ms sui client (palmari).
Io volevo essere sicuro di leggere il file completo, e questo lo è quando
anche il lock è stato scritto. In pratica se c'è il lock il file dati è
scritto sicuramente.
Putroppo ho notato che in due fasi (il kill e il filecopy) sul server
possono esserci errori:
Invia:
  FileCopy FileTemp, MioPath & "\Domanda.txt"
  FileCopy FileTemp, MioPath & "\Domanda.lck" 'qui
Ricevi:
            Kill FileLck			'qui
Probabilmente per un discorso di accesso concorrente.
Metterò una gestione errori ad hoc (come è sui palmari), che in caso di
problemi non elabori niente, e al limite lo faccia al giro successivo (per
quelli col timer), e una sorta di retry automatico all'evento di invio
automatico.
Putroppo già all'inizio avevo espresso dubbi sul scambiare informazioni
tramite files in rete, volendo invece usare una comunicazione tipo socket e
TCPClient/TCPListener o equivalente. Ma è stato deciso di farlo in questo
modo...

       End If
-- 
Greg 

  FileCopy FileTemp, MioPath & "\Domanda.lck"
Anche perchè parliamoci chiaro, questa pezza non è molto bella...
-- 
Ciao Fede
By Chicco Production
http://bcp.freetools.it

>       End If
Allora sono queste:
Kill FileLck
	- Errore 70 Autorizzazione negata
FileCopy FileTemp, MioPath & "\Domanda.lck"
	- Errore 75 Errore di accesso al percorso/file
Il primo è dovuto che la Dir$ vede un file quando non esiste, e cancellando
poi da errore, perchè sicuramente è in scrittura.
Il secondo immagino perchè il palmare in quel momento sta facendo la dir$.
Non vorrei che in realtà ci sia l'antivirus in mezzo che blocca il file,
perchè la Dir$ o File.Exists su .Net non credo blocchino niente.

     Open FileTemp For Binary Access Write Lock Read As #ff
Allora, premetto che non file ad accesso multiplo non ho mai lavorato.
In cosa consiste la differenza?
Cioè il fatto che blocchi il file in lettura, blocca subito anche la Dir$
su quel file, o la File.Exists su .Net?
Perchè a me questo funziona e non da problemi, mentre speravo desse errore:
  Open App.Path & "\1.lck" For Binary Access Write Lock Read As #1
  Debug.Print Dir$(App.Path & "\1.lck")
  Close #1
Dato che su questi file lck mi servono solo a vedere se esistono (semaforo
appunto), e cancellargli una volta acquisito il tutto.
In ogni caso devo gestire l'errore sul server (vb6). I palmari avevano già
i Try Catch e infatti sono una roccia :D
Per ora ho messo, nella routine di kill, se da errore la routine ci passerà
il timer al giro dopo (non è un problema a livello pratico), mentre nel
filecopy, dove non riesco a capire come mai da errore, ho messo un max di 5
retry nel fare il filecopy in caso di errore intervallati da 500ms.

 intervallati da 500ms.
Ma invece dai creare a cancellare file non č piu semplice che tutti scrivano 
il loro stato su di uico file e tutti vanno a leggere?
Non piu di un mese fa c'era un bellissimo esempio dove 2 programmi 
interloqivano su uno stesso pc tramite un file.
Non penso sia molto difficile adattarlo a piu macchine..
-- 
Greg 

 Non penso sia molto difficile adattarlo a piu macchine..
Trovato, è FranzArtiglio che scrive, e qui tutta la discussione:
http://groups.google.it/group/it.comp.lang.visual-basic/browse_thread/thread/f612837183384f6d/1479520b9878d1d6?hl=it&lnk=st&q=#1479520b9878d1d6
Crei un file in memoria, A e B leggono e scrivono questo file.
In questo file A e B si passano le informazioni: quando A deve
minimizzare, chiudere o fare il caffe' a B e viceversa: se (ipotizziamo)
il file in memoria e' di 4 Byte cosi' strutturato:
Byte 1: stato di A (B non ci scrive, legge solo)
Byte 2: stato di B (A non ci scrive, legge solo)
Byte 3: comando per B (A ci scrive, B "reagisce" al
                                  comando e scrive il byte 1
                                  quando "ha fatto").
Byte 4: comando per A (B ci scrive, A "reagisce" al
                                  comando e scrive il byte 2
                                  quando "ha fatto").
Esempio,
11 00  (A e' aperto e normale, B idem)
11 20  (A e' aperto e chiede a B di minimizzarsi)
12 00  (B ha letto il comando, si e' minimizzato e ha
          azzerato il suo byte "comando")
ecc ecc ecc...
Puoi programmare la scrittura/lettura dei comandi tra i 2 file
con un timer (es. ogni 1/2 secondo leggi e reagisci).
-- 
Greg 

 i Try Catch e infatti sono una roccia :D
In questo modo accedi al file in lettura,
e lo blocchi a chiunque lo voglia Leggere o Scrivere (Praticamente a tutti).
private sub Leggi(...)
    On error goto Errore
    Open App.Path & "\1.txt" For Binary Access Read Lock Read Write As #1
        ...
    Close #1
    kill App.Path & "\1.txt"
    exit sub
Errore: 'Esempio gestione errori
    Select case err.number
        case 70: 'e qui ci metti quello che vuoi
    end select
end sub
Spero di esserti stato utile...
-- 
Ciao Fede
By Chicco Production
http://bcp.freetools.it
"Andrea [Work]" <andrea.isw...@gmail.invalid> ha scritto nel 
messaggio news:vwy5laamspy5$.1x47y6bkq2lpb$.dlg@40tude.net...


 il loro stato su di uico file e tutti vanno a leggere?
A me sostanzialmente interessava sapere come dire ad un altro dispositivo:
"Ok, ti ho preparato la roba, puoi andare"
E l'altro:
"Ok, ti ho risposto, puoi andare"
Sostanzialmente cosě funziona. Mettendo in debug un risponditore automatico
a 2msec da entrambe le parti, in 4h di elaborazione ho avuto solo una
decina di errori, comunque gestiti.

 e lo blocchi a chiunque lo voglia Leggere o Scrivere (Praticamente a tutti).
Come puoi vedere, è l'esempio che ho provato.
Quel tipo di lock però non blocca la Dir$ che ti vede il file senza
problemi.
Dato che su quel file faccio solo una Dir$ e un Kill finita l'elaborazione,
alla fine il risultato è uguale, cioè gestire l'errore in quei casi
"strani" di accesso concorrente.
Il problema è che la procedura di elaborazione è troppo ottimizzata e
veloce :D, quindi quando esiste il file lck, e dopo l'elaborazione lo
cancello, è possibile che sia ancora bloccato. Non so se da FileCopy o
magari da un antivirus che sta scansionando il file.
L'unica soluzione che mi viene in mente è appunto gestire l'errore, dato
che in quest'applicazione (che spero sia l'unica in cui devo sfruttare file
di semaforo), posso riacquisire tutto all'evento timer successivo, e anche
acquisire per qualche motivo due volte non è un problema, dato che alla
fine il tutto si riduce ad assegnare un valore ad una proprietà di una
classe, che se è due volte lo stesso non è un problema.

 classe, che se è due volte lo stesso non è un problema.
Dir$ rileva semplicemente la presenza del file.
Devi prima utilizzare Dir$ per vedere se il file che ti interessa è presente
e dopo usi Open per tentare di aprirlo.
Nell'eventualità che non possa aprirlo,
ti verrà restituito un preciso codice d'errore,
che ti dovrai gestire.


 Tnx
Una idea "eretica"....ho capito che parli di palmari!....
TRASFORMA tutto e metti il file come campo di database...i "pal-amari"
hanno dentro ADOce e ti si possono collegare a SQLexpress
Se il palmare ha bisogno di un file...lo chiede al tuo sqlserver...hai
tutti i vantaggi di un DB serio...trigger stored concorrenza
ottimistica pessimistica semafori lanterne e lucciole!
Al palmare arriva uno stream che poi se ne fa quello che vuole...lo
trasforma in file localmente...lo presenta sullo schermo...suona
l'aida...trema e vibra ...quello che vuoi!
...e tu campi più tranquillo e hai una soluzione più professionale e
robusta di un file aperto.
Ad esempio....se il tuo utonto sul server installa il norton
antivirus....e un file per essere disponibile ha bisogno di 700ms
invece di 500???...Se l'utonto cambia hard disk e ne mette uno "made
in chinamerd" e l'accesso fa pena?
Non ne cavi la gambe...il clienti si incazza....e la figura barbina è
tua!
;o)
Ciao!

 ;o)
Bhe fai conto che è un programma fatto ad hoc, e non sarà mai configurato
diversamente.
Anche io appunto pensavo a due soluzioni all'inizio:
 - Invio tutto al palmare e poi questi lavorano, e inviano i risultati alla
fine (quindi select da DB remoto o XML o altro)
 - Invio i dati tramite TCP senza usare file di rete
Poi mi han detto di usare file ecc., e io ho espresso i miei dubbi.
Però fai conto che ho circa 2h da qui a lunedì da poterci dedicare, poi
dovrà essere in funzione lunedì appunto. Il problema di fondo sta sempre
lì, manca il tempo per fare le cose come si deve. E una volta fatte che
funzionano non mi sogno di andare a scoinvolgere tutto.
Ad ogni modo, per quello che fa il programma, se il file non è disponibile
dopo 500ms, lo recupera al timer successivo senza alcun problema.
D'altronde sarebbe la stessa cosa se su una tabella in un DB non si trova
il record pronto, deve recuperarlo dopo.