Posts: 733
Threads: 103
Joined: Apr 2022
Reputation:
14
(05-23-2024, 07:25 PM)Steffan-68 Wrote: I might have another thought.
I'm not particularly a fan of constantly writing to a file and deleting it again.
Since it looks like it's just a Windows program, how about writing stad to a file just using the clipboard?
It would all be in RAM and no HDD access. Interesting idea... Maybe we can try that later.
For now I have it working with DSMan195276's network code.
(Will post soon in Works in Progress.)
Posts: 2,696
Threads: 327
Joined: Apr 2022
Reputation:
217
(05-23-2024, 06:56 PM)DSMan195276 Wrote: (05-23-2024, 05:45 PM)Kernelpanic Wrote: One could almost compare it with a traffic light at an intersection: If North - South is green, then West - East has to wait (red) until it itself is green. If all road users stick to it, there won't be crashed. Unfortunately Steve's approach can't prevent both programs from reading and writing at the same time, I don't think there's a way to do it with read/write file interactions alone.....
It can.
Try these two programs out and watch them interact with a single file:
Code: (Select All)
Open "temp.txt" For Output As #1: Close 'make certain file is blank/new to begin with
Open "temp.txt" For Binary As #1
Do
Select Case checkFile
Case 11
Print "Program 1 has control, is reading file."
readfile
Case 12
Print "Program 1 has control, is writing to file."
writefile
Case 21
Print "Program 2 has control, is reading file."
Case 22
Print "Program 2 has control, is writing to file."
Case Else
Print "File is free for usage."
x = Int(Rnd * 100)
Select Case x
Case 10: writefile 'generate a random write every so often to see if we have issues
End Select
End Select
_Limit 10
Loop
Sub readfile
Dim temp As _Unsigned _Byte
Dim junkdata As Long
temp = 11
Put #1, 1, temp
_Delay .1 'wait 1/10 second to make certian other file isn't also trying to take control
Get #1, 1, temp
If temp <> 11 Then Exit Sub 'other file took control first. We had a race condition and avoided it.
Print "Recieved Data:"
Do Until EOF(1)
Get #1, , junkdata
Print junkdata; ",";
Loop
Print
'finished reading, free up the file now
temp = 0
Put #1, 1, temp
End Sub
Sub writefile
Dim temp As _Unsigned _Byte
Dim junkdata As Long
temp = 12
Put #1, 1, temp
_Delay .1 'wait 1/10 second to make certian other file isn't also trying to take control
Get #1, 1, temp
If temp <> 12 Then Exit Sub 'other file took control first. We had a race condition and avoided it.
Print "Writing Data:"
For i = 1 To 10
junkdata = Int(Rnd * 100) + 1
Put #1, , junkdata
Print junkdata; ",";
Next
Print
'finished reading, free up the file now
temp = 21 'tell the second program that it's now time to read the file!
Put #1, 1, temp
End Sub
Function checkFile~%%
Dim temp As _Unsigned _Byte
Get #1, 1, temp
checkFile = temp
End Function
Code: (Select All)
Open "temp.txt" For Binary As #1
Do
Select Case checkFile
Case 21
Print "Program 2 has control, is reading file."
readfile
Case 22
Print "Program 2 has control, is writing to file."
writefile
Case 11
Print "Program 1 has control, is reading file."
Case 12
Print "Program 1 has control, is writing to file."
Case Else
Print "File is free for usage."
x = Int(Rnd * 100)
Select Case x
Case 10: writefile 'generate a random write every so often to see if we have issues
End Select
End Select
_Limit 10
Loop
Sub readfile
Dim temp As _Unsigned _Byte
Dim junkdata As Long
temp = 21
Put #1, 1, temp
_Delay .1 'wait 1/10 second to make certian other file isn't also trying to take control
Get #1, 1, temp
If temp <> 21 Then Exit Sub 'other file took control first. We had a race condition and avoided it.
Print "Recieved Data:"
Do Until EOF(1)
Get #1, , junkdata
Print junkdata; ",";
Loop
Print
'finished reading, free up the file now
temp = 0
Put #1, 1, temp
End Sub
Sub writefile
Dim temp As _Unsigned _Byte
Dim junkdata As Long
temp = 22
Put #1, 1, temp
_Delay .1 'wait 1/10 second to make certian other file isn't also trying to take control
Get #1, 1, temp
If temp <> 22 Then Exit Sub 'other file took control first. We had a race condition and avoided it.
Print "Writing Data:"
For i = 1 To 10
junkdata = Int(Rnd * 100) + 1
Put #1, , junkdata
Print junkdata; ",";
Next
Print
'finished reading, free up the file now
temp = 11 'tell the second program that it's now time to read the file!
Put #1, 1, temp
End Sub
Function checkFile~%%
Dim temp As _Unsigned _Byte
Get #1, 1, temp
checkFile = temp
End Function
They set the flag for who has control, and skip doing anything unless they have control... Then when they're finished writing, they set the flag so the other program now has control to read.
Note that you can also use LOCK to make certain that only one program can access a file at a time, though I didn't mention it earlier as it's WINDOWS ONLY. https://qb64phoenix.com/qb64wiki/index.php/LOCK
Posts: 1,002
Threads: 50
Joined: May 2022
Reputation:
27
This now reminds me of MySQL and PostgreSQL; that I once had to do with. The file that is currently being written to must of course be locked for other write access. . . otherwise there would be breakage.
This is all very complicated. And therefore very error-prone.
@madscijr, check the design of your program again.
Posts: 733
Threads: 103
Joined: Apr 2022
Reputation:
14
(05-23-2024, 08:30 PM)Kernelpanic Wrote: This now reminds me of MySQL and PostgreSQL; that I once had to do with. The file that is currently being written to must of course be locked for other write access. . . otherwise there would be breakage.
This is all very complicated. And therefore very error-prone.
@madscijr, check the design of your program again. Yup, it was a terrible kludge!
The latest version in WIP now uses DSMAN's network code, seems to be working better.
Posts: 303
Threads: 10
Joined: Apr 2022
Reputation:
44
(05-23-2024, 08:09 PM)SMcNeill Wrote: They set the flag for who has control, and skip doing anything unless they have control... Then when they're finished writing, they set the flag so the other program now has control to read. I mean you didn't really solve the underlying problem, you simply avoided the race by adding a _Delay .1
That said, one-way commutation with three states like you're doing has some potential. I'd still be concerned about caching, especially on Linux and Mac OS where we make use of the C++ file streams, but overall I think it's ok.
Posts: 733
Threads: 103
Joined: Apr 2022
Reputation:
14
(05-23-2024, 10:05 PM)DSMan195276 Wrote: (05-23-2024, 08:09 PM)SMcNeill Wrote: They set the flag for who has control, and skip doing anything unless they have control... Then when they're finished writing, they set the flag so the other program now has control to read. I mean you didn't really solve the underlying problem, you simply avoided the race by adding a _Delay .1
That said, one-way commutation with three states like you're doing has some potential. I'd still be concerned about caching, especially on Linux and Mac OS where we make use of the C++ file streams, but overall I think it's ok. If two programs could share the memory pointers for certain variables, that would be the fastest communication. Of course that opens up other problems, but if it was a bona-fide feature built into and managed by QB64PE, kind of like shared global variables - super global variables, ie shared across 2 or more processes, that might be kinda useful! I'm nowhere near as technical or knowledgable as the other folks here, so it's entirely possible it's not possible or a Bad Idea, but I figure it's worth asking about...
Posts: 2,696
Threads: 327
Joined: Apr 2022
Reputation:
217
05-24-2024, 12:56 AM
(This post was last modified: 05-24-2024, 12:57 AM by SMcNeill.)
(05-23-2024, 10:05 PM)DSMan195276 Wrote: (05-23-2024, 08:09 PM)SMcNeill Wrote: They set the flag for who has control, and skip doing anything unless they have control... Then when they're finished writing, they set the flag so the other program now has control to read. I mean you didn't really solve the underlying problem, you simply avoided the race by adding a _Delay .1
That said, one-way commutation with three states like you're doing has some potential. I'd still be concerned about caching, especially on Linux and Mac OS where we make use of the C++ file streams, but overall I think it's ok. You can skip that delay completely and the flag system will still work. The programs just take turns working with the file.
Program 1 starts up. Creates file. Sets flag for "In use." Writes to file.
Program 2 starts up. File exists. Checks flag. It's in use... does nothing.
Program 1 finishes writing. Sets flag for "Hey you, read this!"... It now enters standby mode.
Program 2 sees flag. Reads file..
Program 1... File still flagged for program 2 use... wait...
Program 2 finishes reading file. Now writes whatever data it needs to send back.
Program 1... File still flagged for program 2 use... wait....
Program 2 finishes writing to file. Now sets flag to "Hey, Program 1, it's your turn!"
Program 1... Reads flag... Takes control...
BINARY lets you read and write at the same time. As long as the first byte in the file is set, you can toggle that back and forth to pass control to whichever program gets to use the file at any given time.
May wear your drive out toggling that one byte over and over and over again, but it's quite doable.
Even with caching, it wouldn't matter, as the control remains with the other program until that cache catches up and updates... though if your cache doesn't push to file for a while, you may end up with both program just being locked in a waiting state until that write finally occurs.
And with that said, I still think the easiest way to do things would be to just OPEN "localhost" for TCP/IP and PUT/GET info back and forth like that between the two programs.
Posts: 733
Threads: 103
Joined: Apr 2022
Reputation:
14
05-24-2024, 02:09 AM
(This post was last modified: 05-24-2024, 02:13 AM by madscijr.)
(05-24-2024, 12:56 AM)SMcNeill Wrote: (05-23-2024, 10:05 PM)DSMan195276 Wrote: (05-23-2024, 08:09 PM)SMcNeill Wrote: They set the flag for who has control, and skip doing anything unless they have control... Then when they're finished writing, they set the flag so the other program now has control to read. I mean you didn't really solve the underlying problem, you simply avoided the race by adding a _Delay .1
That said, one-way commutation with three states like you're doing has some potential. I'd still be concerned about caching, especially on Linux and Mac OS where we make use of the C++ file streams, but overall I think it's ok. You can skip that delay completely and the flag system will still work. The programs just take turns working with the file.
Program 1 starts up. Creates file. Sets flag for "In use." Writes to file.
Program 2 starts up. File exists. Checks flag. It's in use... does nothing.
Program 1 finishes writing. Sets flag for "Hey you, read this!"... It now enters standby mode.
Program 2 sees flag. Reads file..
Program 1... File still flagged for program 2 use... wait...
Program 2 finishes reading file. Now writes whatever data it needs to send back.
Program 1... File still flagged for program 2 use... wait....
Program 2 finishes writing to file. Now sets flag to "Hey, Program 1, it's your turn!"
Program 1... Reads flag... Takes control...
BINARY lets you read and write at the same time. As long as the first byte in the file is set, you can toggle that back and forth to pass control to whichever program gets to use the file at any given time.
May wear your drive out toggling that one byte over and over and over again, but it's quite doable.
Even with caching, it wouldn't matter, as the control remains with the other program until that cache catches up and updates... though if your cache doesn't push to file for a while, you may end up with both program just being locked in a waiting state until that write finally occurs.
And with that said, I still think the easiest way to do things would be to just OPEN "localhost" for TCP/IP and PUT/GET info back and forth like that between the two programs.
Yikes... That all seems a little too "bare metal" for comfort, lol.
I'm sure it could work, the TCP/IP method just seems a lot cleaner, nice and simple!
What about shared variables in memory? One program could use TCP/IP to pass a pointer to the address of the variable to the other EXE, and as long as both of them always write a fixed anount of bytes to it, they could swap values back and forth. It's also kind of low level, I'm just curious if it would perform any faster than pure TCP/IP...
Posts: 303
Threads: 10
Joined: Apr 2022
Reputation:
44
(05-24-2024, 12:56 AM)SMcNeill Wrote: You can skip that delay completely and the flag system will still work. The programs just take turns working with the file.
Even with caching, it wouldn't matter, as the control remains with the other program until that cache catches up and updates... though if your cache doesn't push to file for a while, you may end up with both program just being locked in a waiting state until that write finally occurs. The issue is writefile, both programs call it when the status is zero. Imagine this flow:
Program 1 calls Checkfile, sees zero. Calls writefile
Program 2 calls checkFile, sees zero. Calls writefile
Program 2 calls Put #1 with 22
Program 2 calls Get #1, sees 22, continues
Program 1 calls Put #1 with 12
Program 1 calls Get #1, sees 12, continues
At this point, both programs have continued in writefile and are writing to the file at the same time. The delay effectively prevents this situation simply because the actual code in writefile takes less than .1 seconds to finish writing to the file. Even when both programs enter writefile, the delay means program 1 can't actually start writing until well after program 2 is done.
Caching can be a problem in the same situation, the program might not reread the status code from the file when you do the `Get`. In that situation the order doesn't matter, if they both call `writefile` then they both write to the file because they don't see eachother's status updates (and then like you said, get locked up as they won't see the status to read).
|