Author |
Topic: Re: Help with Multi-user application (Read 1403 times) |
|
roxyryan
New Member
member is offline


Posts: 4
|
 |
Re: Help with Multi-user application
« Reply #9 on: Sep 7th, 2016, 4:57pm » |
|
 Richard good news it seems as though I finally have a multi-user program without having to use any third party database software, and without any API calls! The final clincher was the try/catch clause. I could not it working with 'on error goto' which does not seem to like jumping back into subroutines. But as soon as I used the try/catch clause it started working! It is an amazing enhancement! I have been running my Pub software from 2 programs, one with my left hand and one with my right, deliberately trying to break it, but so far it has has got through without crashing. I want to do some more testing and then will send my code, which is really quite simple at the end of the day. Dermot
|
|
Logged
|
|
|
|
Richard Russell
Administrator
member is offline


Posts: 1348
|
 |
Re: Help with Multi-user application
« Reply #10 on: Sep 7th, 2016, 9:02pm » |
|
on Sep 7th, 2016, 4:57pm, roxyryan wrote:| 'on error goto' which does not seem to like jumping back into subroutines. |
|
Once you've exited the scope of a subroutine you can't jump back in. That is, the GOTO may seem to work but something bad is sure to happen before too long! So if, when an error occurs, you need to jump to a label within a subroutine, put the ON ERROR statement itself within the scope of that subroutine.
Of course I'd rather that you use SEH (try...catch...end try) instead. There's no GOTO involved so no danger that you might, deliberately or by accident, try to jump somewhere you shouldn't.
Richard.
|
|
Logged
|
|
|
|
roxyryan
New Member
member is offline


Posts: 4
|
 |
Re: Help with Multi-user application
« Reply #11 on: Sep 8th, 2016, 09:01am » |
|
Richard I cannot break the program with the code below, it really works. I am sure there is prettier code to achieve the same, but this is simple and it works. While testing I had displays to show when it was "caught" in a conflict, and I only had that happen in the second "catch" shown in the routine. Maybe I dont need the first catch?
' the example below is the code that has to be done for each file, in this case the orders file, #10
Code: ' -------------------------------------------------------
' If a file is to be accessed for read-only then:
gosub [openorders]
' do processing
close #10
' -------------------------------------------------------
' If a file is to be accessed for writing then:
gosub [set.orders.lock]
' do processing
gosub [rel.orders.lock]
' -------------------------------------------------------
[openorders] ' opens the file in the appropriate mode
if file.mode$ = "OUT" then
OPEN ordersname$ FOR random AS #10 len=215
else
OPEN ordersname$ FOR input AS #10 len=215
end if
file.mode$ = "" ' set flag back to default, ie input
FIELD #10,_
1 AS ORlock$,_ ' only used on record 1 (no data held on record 1)
1 AS ORuser$,_ ' only used on record 1
etc other fields
return
' -------------------------------------------------------
[set.orders.lock] ' This subroutine called to open the file and set the lock indicator
waited = 0
gosub [openorders] ' file.mode$ not set, so it defaults to open input mode
[set.orders.lock.repeat]
get #10, 1
if ORlock$ = "Y" then ' Indicator on record 1 of random file
close #10
waited += 1
if waited < 11 then
call delaysub, 500 ' keep trying 10 times
gosub [openorders] ' open in input mode
goto [set.orders.lock.repeat]
end if
for x = 1 to max.users
if ORuser$ = userscodes$(x) then
other.user$ = usersnames$(x)
end if
next x
noticetext1$ = "Orders File is locked by " + other.user$ ' This message should never normally appear
notice.x = 20: notice.y = 60: gosub [notice.box] ' (my own notice routine)
waited = 0
gosub [openorders] ' open in input mode
goto [set.orders.lock.repeat]
else
close #10
try
file.mode$ = "OUT": gosub [openorders] ' open in read/write mode
catch
call delaysub, 100
gosub [openorders]
goto [set.orders.lock.repeat]
end try
try
ORlock$ = "Y" ' set the lock now to prohibit other users
ORuser$ = user.code$ ' the user code for this user
put #10, 1
catch
close #10
call delaysub, 100
gosub [openorders] ' open in input mode
goto [set.orders.lock.repeat]
end try
end if
return
' -------------------------------------------------------
[rel.orders.lock] ' Release the lock and close the file
get #10, 1
ORlock$ = "N" ' Indicates no longer locked
ORuser$ = ""
put #10, 1
close #10
return
' -------------------------------------------------------
sub delaysub delaytime
timer delaytime, [pause]
wait
[pause]
timer 0
end sub
' -------------------------------------------------------
|
|
|
|
Richard Russell
Administrator
member is offline


Posts: 1348
|
 |
Re: Help with Multi-user application
« Reply #12 on: Sep 8th, 2016, 1:29pm » |
|
on Sep 8th, 2016, 09:01am, roxyryan wrote:| I only had that happen in the second "catch" shown in the routine. Maybe I dont need the first catch? |
|
So, that means the OPEN never failed but the PUT did? I expect the explanation is that you opened the file for RANDOM (in order to preserve the existing contents) which probably succeeds even if the file is currently being written by another user. Then when you try to write to the file the sharing violation is triggered.
Personally I'd be inclined to leave the first TRY clause in place. It doesn't do any harm and you might find that the behaviour is different if (for example) the file is stored on a shared network server running a different OS.
I notice that you haven't randomized the delays. You'll probably get away with it, but it does increase the probability of a deadlock if two users keep retrying simultaneously.
Incidentally I don't know if this limitation of LBB is going to hit you, but there is a maximum of eight simultaneously-open random files.
Richard.
|
|
|
|
roxyryan
New Member
member is offline


Posts: 4
|
 |
Re: Help with Multi-user application
« Reply #13 on: Sep 8th, 2016, 2:36pm » |
|
Richard Thanks for the reminder, yes I will randomise the delays. Also now that I am only opening when needed, I wont be hitting that 8 file limit, I have a maximum of 3 or 4 open at a time Dermot
|
|
Logged
|
|
|
|
Mystic
Junior Member
member is offline


Gender: 
Posts: 53
|
 |
Re: Help with Multi-user application
« Reply #14 on: Sep 8th, 2016, 2:39pm » |
|
on Sep 8th, 2016, 1:29pm, Richard Russell wrote:I notice that you haven't randomized the delays. You'll probably get away with it, but it does increase the probability of a deadlock if two users keep retrying simultaneously. |
|
Ah ha! Was wondering about the randomization of the delay. Now it makes sense! I didn't even think of the potential user-standoff occurring.
I love learning new things.
Thanks Richard, and everyone for a great discussion.
|
|
Logged
|
- Rick
|
|
|
Richard Russell
Administrator
member is offline


Posts: 1348
|
 |
Re: Help with Multi-user application
« Reply #15 on: Sep 11th, 2016, 01:08am » |
|
on Sep 8th, 2016, 09:01am, roxyryan wrote:| I cannot break the program with the code below, it really works. |
|
I've only just noticed this:
Code: try
file.mode$ = "OUT"
gosub [openorders] ' open in read/write mode
catch
call delaysub, 100
gosub [openorders]
goto [set.orders.lock.repeat]
end try I need hardly say that if the GOTO here is ever taken the program will almost certainly suffer a slow and painful death. It takes some bravado to jump out of a Structured Exception Handling clause with a GOTO - the antithesis of structured programming!!
Richard.
|
|
Logged
|
|
|
|
roxyryan
New Member
member is offline


Posts: 4
|
 |
Re: Help with Multi-user application
« Reply #16 on: Sep 11th, 2016, 12:05pm » |
|
Richard Thank you for the kind words, but I think I told you previously that I had displays in my testing to prove which path the program followed. The program most certainly goes through this "goto" statement, and it works, every time. As I said previously, there are no doubt prettier statements to achieve the same, but this works. Dermot
|
|
Logged
|
|
|
|
Richard Russell
Administrator
member is offline


Posts: 1348
|
 |
Re: Help with Multi-user application
« Reply #17 on: Sep 11th, 2016, 1:06pm » |
|
on Sep 11th, 2016, 12:05pm, roxyryan wrote:| The program most certainly goes through this "goto" statement, and it works, every time. |
|
Well, it rather depends on how you define "works". It is certainly the case that executing a TRY statement, but not executing the matching END TRY statement, will leave LBB in an unstable state. For example, if a subsequent error were to occur (for any reason) it would not be reported, and LBB would most probably crash. So at the very least debugging the program would be made much more difficult because even a trivial typo could result in an unexplained non-obvious failure.
It's a bit like jumping out of a loop (like a FOR loop or a WHILE loop) with a GOTO. That may appear to 'work', and indeed the program may keep running apparently correctly for hours or more, but eventually it will crash out for no obvious reason. In those cases there is an 'official' way to exit the loop prematurely, but there's no legitimate way of terminating a TRY clause other than executing the END TRY.
It's the very fact that the incautious use of GOTO is so prone to creating a 'fragile' program that many people (including me) will say it should ideally never be used at all. It's a subject that creates a lot of heated argument, and some people vociferously defend the use of GOTO, but even its most ardent supporters have to admit that it must be used with extreme care.
It's a basic tenet of Software Engineering that you cannot ascertain whether a program works or not by testing alone. Testing is valuable, but in most cases it cannot hope to exercise every possible path through a program, nor confirm that a program will remain stable even if left running for a very long time. 'Following the rules' is just as important as testing for ensuring that a program is reliable and resilient.
Richard.
|
|
|
|
|