Announcement

Collapse
No announcement yet.

Is FREEFILE thread safe

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Is FREEFILE thread safe

    Hi,

    I am using FREEFILE in threads. Is it safe?

    Thanks.

  • #2
    Shirlun --

    I have been told by Tech Support that, in strictly technical terms, FREEFILE is 100% thread safe, but consider this...

    If thread #1 uses FREEFILE to obtain a free file number, and then, in the tiny fraction of a second that will take place before thread #1 can OPEN it, thread #2 uses FREEFILE, thread #2 will be given the same file number. That is perfectly normal and expected, since at the instant that the program asked for a free number, that number was still free. So then thread #1 would open it, and when thread #2 tried to open the same number it would fail. The longer the delay between the use of FREEFILE and OPEN, the greater the risk of failure.

    -- Eric


    -------------
    Perfect Sync: Perfect Sync Development Tools
    Email: mailto:[email protected][email protected]</A>

    "Not my circus, not my monkeys."

    Comment


    • #3
      This is going to sound like a dumb question, but why must it be used prior to being allocated by FREEFILE?

      It would seem to me, that lets say you had 20 files to open, if you did assignment by FREEFILE, you could go on about your business and open them at your convenience ??


      -------------
      Scott Turchin


      Scott Turchin
      MCSE, MCP+I
      http://www.tngbbs.com
      ----------------------
      True Karate-do is this: that in daily life, one's mind and body be trained and developed in a spirit of humility; and that in critical times, one be devoted utterly to the cause of justice. -Gichin Funakoshi

      Comment


      • #4
        Scott,
        FREEFILE doesn't do the allocations. Try this and you'll see an error

        i = FreeFile
        j = FreeFile

        Open "somefile.txt" for input as #i
        Open "someotherfile.txt" for input as #j

        You'll get an error because i and j are the same thing.

        --Don
        Don Dickinson
        www.greatwebdivide.com

        Comment


        • #5
          To prevent parallel execution, I declare global variable (for example, Busy) and do in thread approx.
          While Busy <> 0: Sleep 20: Wend: Busy = 1
          <protected fragment>
          Busy = 0

          I think, that in practice this is safety code, because Windows is not really multi-tasking OS.
          But theoretically is there any possibility that Windows will interrupt one thread before Busy = 1 and gives control to another thread ?

          Comment


          • #6
            Semen --

            That is a good technique, but it is not bulletproof. Statistically, it will fail every so often. And when it does, it would be extremely difficult to troubleshoot.

            For best results, you should use a Critical Section or a Mutex, which are "objects" that are provided by the API for exactly the purpose you are describing.

            -- Eric

            -------------
            Perfect Sync: Perfect Sync Development Tools
            Email: mailto:[email protected][email protected]</A>

            "Not my circus, not my monkeys."

            Comment


            • #7
              Eric --
              I don't doubt in your words, but theoretically it's not clear for me, why CALL API-function (which includes preparatory operations - loading registers and so on) is more safety than single statement Busy = 1 ?



              [This message has been edited by Semen Matusovski (edited January 03, 2000).]

              Comment


              • #8
                Semen --

                > But it's not clear for me, why CALL API-function
                > (which includes preparatory operations loading
                > registers and so on) is more safety than single
                > statement Busy = 1 ?

                Because it is not possible to predict when Windows will decide to allow a thread to execute.

                Consider your code...

                Code:
                While Busy <> 0
                    Sleep 20
                Wend
                Busy = 1
                <protected fragment>
                Busy = 0
                When the code is executed, if another thread has set Busy=1 this thread will wait for it to be set to zero. But it is possible for the threads to be executing in such a way that Windows stops executing this thread in between the WEND and the BUSY=1 lines, and allows another thread to set Busy=1. Look at it this way... If Windows is using extremely long "time slices" then it is very likely that all of that code will be executed as a block, and everything will work fine. But there is a very small chance that Windows will switch the processor to the other thread right after the WEND, and if it does, remember that the time slice is very long so the other thread will have a very long time to set Busy=1. If the time slices are very short, then the odds increase that Windows will switch right after the WEND, but because the time slices are very short the other thread will not execute very many lines of code before control is returned to this thread, so the odds are reduced. Either way, there is a small chance that the "worst case" will happen and your program will malfunction.

                > (which includes preparatory operations loading
                > registers and so on)

                It really doesn't require anything like that. At the very beginning of your program, add code that looks something like this...

                Code:
                DIM gtCritSect AS GLOBAL CRITICAL_SECTION
                InitializeCriticalSection gtCritSect
                Then surround critical code like this...

                Code:
                EnterCriticalSection gtCritSect
                '<protected fragment>
                LeaveCriticalSection gtCritSect
                Windows will do the rest. It will make sure that no two threads execute that "surrounded"
                section of code at the same time.

                It is also possible to protect two or more sections of code with the same Critical Section. For example, if one thread can perform a REDIM operation on an array and another thread can read/write array values, you would surround all of the code that accesses the array with the same global critical section (gtArrayInUse or something like that) so that one thread could never (for example) access the array while another thread was REDIMing it. Something like REDIM PRESERVE, which looks simple because it is just one line of code, is actually very complex and can take a significant amount of time to execute. Imagine what would happen if, in the middle of a large REDIM PRESERVE operation, Windows gave the processor to another thread that accessed the array. The second thread might be trying to use an array that was 50% re-dimensioned and 50% not re-dimensioned. If the second thread changed an array element that had already been processed, one thing would happen, and if it changed an array that had not yet been processed, something else would happen.

                Threads are very hard to visualize, especially when you first start using them. As far as I know, the only 100% sure way to keep two threads from "stepping on each other" is to use a Critical Section or a Mutex. If you are writing a single, multi-threaded app, then Critical Sections are faster and more efficient. If you must synchronize two different apps, then you will have to use a Mutex.

                HTH.

                -- Eric

                [This message has been edited by Eric Pearson (edited January 03, 2000).]
                "Not my circus, not my monkeys."

                Comment


                • #9
                  Semen, it is because Windows can perform a context switch between your threads at *ANY moment, and there is a chance that the BUSY = 1 code was not completed before the 2nd thread can test the value of BUSY. When the context switch comes back, the 1st thread may still assume that BUSY is safe to change... BOOM... both of your threads will now incorrectly assume BUSY is under their control!

                  A critical section will prevent this from occuring. See Rector/Newcomer's "Win32 Programming" for a more in-depth explanation!



                  -------------
                  Lance
                  PowerBASIC Support
                  ( mailto:[email protected][email protected]</A> )
                  Lance
                  mailto:[email protected]

                  Comment


                  • #10
                    Eric --
                    I fully accept your variant, because it's difficult to believe that Windows is able to execute two API-functions (from different tasks) in one moment (right?).
                    Thanks a lot for explanation and example.

                    Lance --
                    I lost enough time to receive answers on some simple questions from amazon
                    (they are able to delivery to Moscow; how to pay - I wanted, like always, bank to bank, but they do not accept this traditional method - interesting ...). In Russian conditions it's not very safety to use electronic cards, first of all, through Internet.
                    But, ok, books already paid and I hope to see them next week.



                    [This message has been edited by Semen Matusovski (edited January 03, 2000).]

                    Comment


                    • #11
                      Let us not forgot machines with multiple CPU's (which is becoming more common). Where it's possible for two threads to "truly" execute simultaneously.

                      --Dave


                      -------------
                      PowerBASIC Support
                      mailto:[email protected][email protected]</A>

                      Home of the BASIC Gurus
                      www.basicguru.com

                      Comment


                      • #12

                        Well you could always add code to check if the file was opened, if not then use FREEFILE again and reopen, say 'Goto TryAgain:'.


                        -------------
                        Kev G Peel
                        KGP Software
                        Bridgwater, UK.
                        mailto:[email protected][email protected]</A>

                        Comment


                        • #13
                          unfortunately kev, your solution is no stronger to that posed by semen using a variable... multiple threaded applications pose a whole new range of risks to code that will execute perfectly in a single-threaded application... using synchronization "objects" is the only way to ensure that code (such as discussed in this thread) remains stable.

                          btw, did anyone bother to read the snippet on synchronization i recently posted a hyperlink to in the third-party forum?





                          -------------
                          lance
                          powerbasic support
                          ( mailto:[email protected][email protected]</a> )
                          Lance
                          mailto:[email protected]

                          Comment


                          • #14
                            Semen,

                            The Mutex approach is better but you could use the next best which is very old:

                            While Busy <> 0
                            Sleep 20
                            Wend
                            INCR Busy
                            <protected fragment>
                            DECR Busy

                            Still not fail safe but better than Busy = 1 and Busy = 0


                            Peter.
                            [email protected]

                            Comment


                            • #15
                              BTW, as you are talking of file operations in threads, be aware that PBDLL6 / PBCC2 use 64-bit variables for file operations. That means that you HAVE to use a mutex / critical section if you perform ANY file operation. It is possible (since we are all using 32-Bit variables) that the first step of a 64-bit operation is cancelled and the "partly ready" value is read by another thread which does not know what is going on.

                              It's also not recommended NOT to use 64-bit variables, because most HD's are already greater than 2GB (and files might be, too). Besides, you don't know what PB is doing internally.

                              This kind of bug is extremely hard to find.

                              -------------
                              Daniel
                              [email protected]

                              [This message has been edited by Daniel Modler (edited January 04, 2000).]

                              Comment


                              • #16
                                BTW, as you are talking of file operations in threads, be aware that PBDLL6 / PBCC2 use 64-bit variables for file operations. That means that you HAVE to use a mutex / critical section if you perform ANY file operation. It is possible (since we are all using 32-Bit variables) that the first step of a 64-bit operation is cancelled and the "partly ready" value is read by another thread which does not know what is going on
                                Just to be clear, you only need to worry about using synchronization objects such as mutex's or critical sections if you need to access the same data within a file, or update memory, etc, in more than one thread at the same time. In multi-threaded applications that do not "share" data (ie, files, variables, etc) between threads then synchronization objects will not often be necessary.

                                The term "cancelled" in the above quote is technically wrong: better terminology would be "context switch" or "task switch".

                                The following is my summation of Rector/Newcomer's "Win32 Programming" explanation: if a 64-bit variable is stored as two 32-bit values, then during update of the value stored in those memory locations, there is always a chance that a context switch may occur when only one half of the variable's 64-bits has been written. At this point, the value of the variable is "undefined", until the context switch reverts back and the update is complete. ie, during the context switch the variable is "1/2 updated".

                                Trouble starts when a second thread tries to use the "undefined" value stored in the variable... all sorts of problems can occur, such as further data corruption or a GPF (depending on what the code uses this variable for).

                                I hope that is a bit clearer

                                -------------
                                Lance
                                PowerBASIC Support
                                ( mailto:[email protected][email protected]</A> )
                                Lance
                                mailto:[email protected]

                                Comment


                                • #17
                                  Lance,

                                  The English we speak in Austria is very bad {g}, I was happy to know "cancel". I wanted to say what you have made clear then.

                                  Luckily there is a German version of Petzold...

                                  Regards

                                  -------------
                                  Daniel
                                  [email protected]

                                  Comment

                                  Working...
                                  X