In the PowerBASIC for DOS forum I have been advised to get, and did, the BASICally Speaking issue for December 1995, for Michael Mattias's excellent article on Multi-User programming. An earlier query of mine ragrading error 75 in PB/DLL 6.0 which, for the identical code in PB/DLL 5.0 does not occur, in conjunction with Michael's mention of LOGICAL locking of files/records, set me thinking and experimenting.
This code is compiled under PB/DLL 6.0, in order to test the result of
reading the same file (or record) twice, absolutely simultaneously, without ANY network conditions being set - no ACCESS/LOCK nor locking or unlocking.
The Delphi code is below: of these, there are TWO, containing exactly the same code, only having different "project" and "unit" names and
different positions of displaying the MessageDlgPos. Both call an identical DLL function (ReadIt) in its own DLL (ReadArec.DLL and
ReadBrec.DLL).
All of this is based on the not unreasonable assumption that the hardware (file server disk read/write heads etc.) CANNOT be in more than one place at any one instant in time.
The two Delphi modules produce two little forms on screen, each with
a button (Button1). By pressing these, one after the other (and there is no more than a second delay between) the two ReadIt functions are launched in succession.
These first ensure that the timer is NOT at a quarter-minute interval, and then waits until the end of the current 15 second interval to open, read and close the little file (plain text). Since both instances utilise the same timer, both should leap into action at the same instant (or very close to it).
What happens after the buttons are clicked to start the sequence, is that there is a delay (the remainder of the fifteen seconds) and then
BOTH messages (MessageDlgPos) pop up, simultaneously, as near as may be discerned. Repeating the experiment ad nauseum has so far failed to produce any errors.
-----------------------------------------------------------------------
Michael's article on LOGICAL file locking, then, seems to be the preferable way to go. My file structure is already established, so that I work around the "flag" byte by instead using a small new file called (say) OPENFILE. This is a binary file, i.e., a simple string.
Whenever a file needs to be READ FROM or WRITTEN TO, anywhere in the system, it is now possible to call a funtion (e.g., StatusOf"(as long)) as in --
n&=StatusOf("Debtors,15,15) (random file, from/to record number)
n&=StatusOf("ProdType,0,0) (sequential file from 0 to lof("ProdType))
n&=StatusOf("EstIndex,78,156) (binary file, from/to byte)
StatusOf checks for the presence of the parameters in OPENFILE; if absent, these parameters are added to OPENFILE and written to disk, and returns a zero. If the parameters are present, it delays half a second,
then reopens OPENFILE and checks again, until the file should be free,
at which point it may exit with a zero value. The number of retests may be restricted to a realistic (time) maximum after which a message to the user is displayed with suitable options (e.g., retry some more, or abort - if feasible). In fact, if the logon name/password/ID of users are added to the OPENFILE entries, it would even be possible to produce a juicy character analysis of defaulters.
When the file or record has been read/written then, unless required otherwise, a very simple routine is used to reverse the OPENFILE records by removing the identical paramenters and refiling to disk.
Like binary files, this frees one from predefined conditions and/or restrictions as well as unknown differences in networking software from different vendors, and for very little extra work, one gains more control over what needs to be done.
Of course, that is, if there are no Black Holes in all of this.
This code is compiled under PB/DLL 6.0, in order to test the result of
reading the same file (or record) twice, absolutely simultaneously, without ANY network conditions being set - no ACCESS/LOCK nor locking or unlocking.
The Delphi code is below: of these, there are TWO, containing exactly the same code, only having different "project" and "unit" names and
different positions of displaying the MessageDlgPos. Both call an identical DLL function (ReadIt) in its own DLL (ReadArec.DLL and
ReadBrec.DLL).
Code:
----------------------------------------------------------------------- #Compile Dll "ReadArec.DLL" #Debug Error On Function ReadIt Alias "ReadIt" Export As String On Error GoTo RdErr Ent: x$=Str$(Timer) y$=x$ x$=Left$(x$,Instr(x$,".")-1) x$=Right$(x$,2) x#=Val(x$) If x# Mod 15=0 Then ent bgn: x$=Str$(Timer) y$=x$ x$=Left$(x$,Instr(x$,".")-1) x$=Right$(x$,2) x#=Val(x$) If x# Mod 15<>0 Then bgn frf&=FreeFile Open "\QX\TestFile" For Binary As frf& Base=0 Seek frf&,0 Get$ frf&,Lof(1),e$ Close frf& Function=e$ Exit Function RdErr: MsgBox("Error"+Str$(Err)+" in ReadBrec") End Function ----------------------------------------------------------------------- Delphi/Pascal: var frmReadThree: TfrmReadThree; ipa: string; function ReadIt: PChar; stdcall; external 'ReadArec.dll'; implementation {$R *.DFM} procedure TfrmReadThree.Button1Click(Sender: TObject); begin ipa := ReadIt; MessageDlgPos('Ipa: '+ipa, mtInformation, [mbOk], 0, 350, 248); Button1.SetFocus; end; -----------------------------------------------------------------------
The two Delphi modules produce two little forms on screen, each with
a button (Button1). By pressing these, one after the other (and there is no more than a second delay between) the two ReadIt functions are launched in succession.
These first ensure that the timer is NOT at a quarter-minute interval, and then waits until the end of the current 15 second interval to open, read and close the little file (plain text). Since both instances utilise the same timer, both should leap into action at the same instant (or very close to it).
What happens after the buttons are clicked to start the sequence, is that there is a delay (the remainder of the fifteen seconds) and then
BOTH messages (MessageDlgPos) pop up, simultaneously, as near as may be discerned. Repeating the experiment ad nauseum has so far failed to produce any errors.
-----------------------------------------------------------------------
Michael's article on LOGICAL file locking, then, seems to be the preferable way to go. My file structure is already established, so that I work around the "flag" byte by instead using a small new file called (say) OPENFILE. This is a binary file, i.e., a simple string.
Whenever a file needs to be READ FROM or WRITTEN TO, anywhere in the system, it is now possible to call a funtion (e.g., StatusOf"(as long)) as in --
n&=StatusOf("Debtors,15,15) (random file, from/to record number)
n&=StatusOf("ProdType,0,0) (sequential file from 0 to lof("ProdType))
n&=StatusOf("EstIndex,78,156) (binary file, from/to byte)
StatusOf checks for the presence of the parameters in OPENFILE; if absent, these parameters are added to OPENFILE and written to disk, and returns a zero. If the parameters are present, it delays half a second,
then reopens OPENFILE and checks again, until the file should be free,
at which point it may exit with a zero value. The number of retests may be restricted to a realistic (time) maximum after which a message to the user is displayed with suitable options (e.g., retry some more, or abort - if feasible). In fact, if the logon name/password/ID of users are added to the OPENFILE entries, it would even be possible to produce a juicy character analysis of defaulters.
When the file or record has been read/written then, unless required otherwise, a very simple routine is used to reverse the OPENFILE records by removing the identical paramenters and refiling to disk.
Like binary files, this frees one from predefined conditions and/or restrictions as well as unknown differences in networking software from different vendors, and for very little extra work, one gains more control over what needs to be done.
Of course, that is, if there are no Black Holes in all of this.
Comment