Announcement

Collapse
No announcement yet.

Multi-Threading

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

  • Multi-Threading

    OK, here's the deal: I'm trying to create a multi-threading option in my PB DLL. Lets call it Test.dll. This is used in a multi-user environment and works great and very fast but I found a faster way to a certain sub. This new routine is less solid but a lot faster.
    So what I want to do is call both the slow and fast routine with the idea like this: if the fast routine does not provide a result, test.dll can wait for the results of the slow routine. This way, my program keeps its speed like it is now but if the fast routine provides results it is a lot faster.

    Let me point out that I'm a newbee at multi-threading, read the Jedi piece (and got confused), read the PB help file on THREAD (which is just a real easy program, so didn't do the trick for me).

    So I have one base routine from which I call my two routine. Here's some code.
    It might be an idea to expand this example a little further later on, cos I'm quit sure that I'm not the only one who's got no clue on how to do this.


    So here's the example where global info is passed to the routines

    Code:
    #COMPILE EXE "C:\Temp2\MT_TEST.EXE"
    $INCLUDE "WIN32API.INC"
    
    GLOBAL InputString AS STRING
    GLOBAL OutputString AS STRING
    
    SUB FastRoutine(BYVAL x AS LONG)
        
        IF LEFT$(InputString, 1) = "$" THEN
            OutputString = "Fast OK"
        END IF
        
        SLEEP 50
        
    END SUB
    
    SUB SlowRoutine(BYVAL x AS LONG)
    
        IF RIGHT$(InputString, 1) = "$" THEN
            OutputString = "Slow OK"
        END IF
        
        SLEEP 5000
        
    END SUB
    
    
    FUNCTION PBMAIN() AS LONG
        
        InputString = "$test$"
    
        DIM x1 AS LONG
        DIM x2 AS LONG
        DIM s1 AS LONG
        DIM s2 AS LONG
    
        ' Start both routines, the slow one first
    
        OutputString = ""
    
        x1 = GetCurrentThreadID()
        THREAD CREATE SlowRoutine(0) TO x1
        x2 = GetCurrentThreadID()
        THREAD CREATE FastRoutine(0) TO x2
    
        ' Then wait for the outcome of the fastroutine
        DO WHILE s1
            THREAD STATUS x2 TO s1
        LOOP
        IF OutputString = "" THEN
            ' if no result, wait for the outcome of the slowroutine
            DO WHILE s2
                THREAD STATUS x1 TO s2
            LOOP
            IF OutputString <> "" THEN
                MSGBOX "SlowRoutine provided result" + OutputString
            ELSE
                MSGBOX "Both routines didn't provide results"
            END IF
        ELSE
            MSGBOX "FastRoutine provided result" + OutputString
        END IF
    
    END FUNCTION

    Question:
    Must the threads be functions or can they also be sub (like in this example)?

    Question:
    Why is the result "Both routines didn't provide results"?

    Question:
    Is it OK to use the Create Thread, but with 0, or should I use 0 and 1? Also for multi-user? Or should I find a way to set an array keeping track of the currently called sub indexes?

    I got some more questions, but I leave them for later.


    Hope someone can help.
    -- Jeroen


    ------------------

  • #2
    Jeroen...

    Rather than try to explain the flaws in your example code, I simply revised it. By reviewing the
    following code, you should be able to see where you need to make your changes...
    Code:
    #COMPILE EXE "C:\Temp2\MT_TEST.EXE"
    $INCLUDE "WIN32API.INC"
    
    
    GLOBAL InputString AS STRING
    GLOBAL OutputString AS STRING
    
    
    SUB FastRoutine(BYVAL x AS LONG)
       SLEEP 50
       IF LEFT$(InputString, 1) = "$" THEN
          OutputString = "Fast OK"
       END IF
    END SUB
    
    
    SUB SlowRoutine(BYVAL x AS LONG)
       SLEEP 5000
       IF RIGHT$(InputString, 1) = "$" THEN
          OutputString = "Slow OK"
       END IF
    END SUB
    
    
    FUNCTION PBMAIN() AS LONG
       LOCAL hSlowThread AS LONG
       LOCAL hFastThread AS LONG
       LOCAL Result AS LONG
       OutputString = ""
       InputString = "$Test$"
       ' Start both threads (slow one first)
       THREAD CREATE SlowRoutine(0) TO hSlowThread
       THREAD CREATE FastRoutine(0) TO hFastThread
       ' Wait for the outcome
       DO
       LOOP WHILE OutputString = ""
       ' Close both threads
       THREAD CLOSE hSlowThread TO Result
       THREAD CLOSE hFastThread TO Result
       ' Display first result obtained
       MSGBOX OutputString
    END FUNCTION
    Timm

    [This message has been edited by Timm Motl (edited October 20, 2000).]
    mailto:[email protected]
    Tsunami Record Manager

    Comment


    • #3
      Thanks a lot, this works a lot better already.
      Just one thing, suppose only the inputstring changes to something which doesn't activate the outputstring? How do you 'interrupt' the do while or is this not possible?

      Regards
      Jeroen

      ------------------

      Comment


      • #4
        Jeroen...

        Without knowing what your application is doing, that's a tough question to answer. The simplest way would be to
        use a GLOBAL LONG variable as a "flag" (set to %TRUE by the SUBs when finished) that can be monitored in your
        DO / LOOP WHILE line.

        Good Luck.

        Timm

        [This message has been edited by Timm Motl (edited October 20, 2000).]
        mailto:[email protected]
        Tsunami Record Manager

        Comment


        • #5
          Hi Timm (or anyone who can help), hope you help one more time. Why doesn't this compile???
          It provides the error: Duplicate Name Definition on the line "THREAD CLOSE Parse_Slow TO result" after "If Hit = 1 Then".
          I have not used any of the variables before or as globals.

          I got a main sub, calling two subs using multi-threading.
          For Parse_Fast a result becomes 1, no result is 2. For Parse_SLow a result becomes 3, no result is 4.

          Here's the code:

          Code:
          #COMPILE DLL "C:\PBDLL\MT_TEST\MT.DLL"
          
          $INCLUDE "C:\PBDLL\WIN32API.INC"
          DECLARE SUB Error()
          DECLARE SUB Parse_Slow(BYVAL x as long)
          DECLARE SUB Parse_Fast(BYVAL x as long)
          
          GLOBAL Hit AS LONG
          
          SUB Error()
              MSGBOX "Error"
          END SUB
          
          SUB Parse_Slow(BYVAL x AS LONG)
              ' action
          END SUB
          
          SUB Parse_Fast(BYVAL x AS LONG)
              ' action
          END SUB
          
          SUB Parse
              LOCAL result AS LONG
              LOCAL hSlowThread AS LONG
              LOCAL hFastThread AS LONG
          
              LOCAL ThreadIDSlow AS LONG
              LOCAL ThreadIDFast AS LONG
          
              Hit = 0
              THREAD CREATE Parse_Slow(0) TO hSlowThread
              THREAD CREATE Parse_Fast(0) TO hFastThread
          
              ' SQLHit becomes:
                  ' 1 result at _Fast
                  ' 2 no result at _Fast
                  ' 3 result at _Slow
                  ' 4 no result at _Slow
              DO WHILE Hit = 0
              LOOP
              IF Hit = 1 THEN
                  ' _Fast provides result: close slow as well
                  THREAD CLOSE Parse_Slow TO result
                  THREAD CLOSE Parse_Fast TO result
          
              ELSEIF Hit = 2 THEN
                  ' fast ready: no result: wait for >FB<
                  THREAD CLOSE Parse_Fast TO result
                  DO WHILE Hit < 3
                  LOOP
                  THREAD CLOSE Parse_Slow TO result
                  IF Hit = 3 THEN
                      ' result
                  ELSEIF Hit = 4 THEN
                      CALL Error()
                  END IF
          
              ELSEIF Hit = 3 THEN
                  ' _slow done before _Fast but with result
                  THREAD CLOSE Parse_Slow TO result
                  THREAD CLOSE Parse_Fast TO result
          
              ELSEIF Hit = 4 THEN
                  ' _slow done before _Fast bith no result: wait for _Fast
                  THREAD CLOSE Parse_Slow TO result
                  DO WHILE Hit <> 1 AND Hit <> 2
                  LOOP
                  THREAD CLOSE Parse_Fast TO result
                  IF Hit = 1 THEN
                      ' result
                  ELSEIF Hit = 2 THEN
                      CALL Error()
                  END IF
              ELSE
                  ' Safe guard
                  THREAD CLOSE Parse_Slow TO result
                  THREAD CLOSE Parse_Fast TO result
          
              END IF                 
          
              MSGBOX "DONE"
          
          END SUB

          ------------------


          [This message has been edited by jeroen brouwers (edited October 29, 2000).]

          Comment


          • #6
            Hi,
            I found the result already:
            the THREAD CLOSE should be used with the handle, i.e. hSlowThread and hFastThread, instead of the names.

            Yet, in multi-user environments, should a thread always be started with 0 or should I use GetCurrentThreadID()??
            Another yet, why does the compiler 'crash' a few lines down (doesn't matter what code)? It provides a 'statement too complex'.
            Thanks in advance

            Jeroen

            ------------------




            [This message has been edited by jeroen brouwers (edited October 29, 2000).]

            Comment


            • #7
              Jeroen --

              > Must the threads be functions or can they
              > also be sub (like in this example)?

              They must be FUNCTIONs. The docs say "This function is presumed to take exactly one long integer byval as a parameter, and returns a long integer result." Since a SUB can't return a result of any kind, a SUB can't meet the requirements of THREAD CREATE.

              > Is it OK to use the Create Thread, but
              > with 0, or should I use 0 and 1?

              That value is strictly for your program's use. PB does not care what value you use, but (per the above) you must pass "exactly one long integer byval as a parameter". Pass zero, or %MAXLONG, or whatever you want. It will make no difference.

              Also, it is very dangerous to use the same GLOBAL string variable in two different threads. Because of the way Windows works, this can lead to many different, difficult-to-find problems. Each GLOBAL value must be either 1) limited to a single thread or 2) "synchonized" so that no two threads can possibly access it at the same time.

              Also, loops like this:

              Code:
              DO WHILE Hit = 0
              LOOP
              ...should always contain a SLEEP 1, or they can monopolize the CPU and keep other threads (and other programs) from executing. This is especially true on 9x systems, but even on NT and 2000 systems a DO/LOOP like that can drag down the entire system, reducing processing speed to a crawl.

              > why does the compiler 'crash' a few lines
              > down (doesn't matter what code)?
              > It provides a 'statement too complex'.

              You should boil down your program to the smallest possible example that still shows this behavior, and post a compilable example here. (Or submit it to PB support if it is proprietary.)

              -- Eric



              ------------------
              Perfect Sync: Perfect Sync Development Tools
              Email: mailto:[email protected][email protected]</A>
              "Not my circus, not my monkeys."

              Comment


              • #8
                Hi Eric, thanks a lot (again).

                OK, why aren't you writing a proper manual about multi-threading. This is the best practical advice I've gotten so far.
                Anyway, I changed the threadID to 500, just to make a difference. I changed my subs to functions.

                So now it compiles but provides the error that this isn't a valid WIN32 application.
                So what am I doing wrong in this code

                Code:
                #COMPILE DLL "C:\MT_TEST.exe"
                $INCLUDE "C:\Sparker\SQLTools\SQL_PRO2.INC"
                $INCLUDE "C:\Sparker\SQLTools\WIN32API.INC"
                
                GLOBAL QString AS STRING
                GLOBAL SQLHit AS LONG
                GLOBAL OutputString AS STRING
                
                FUNCTION PBMAIN() AS LONG
                    
                    QString = "teststring"
                    CALL SQL_Parse
                
                END FUNCTION
                
                SUB SQL_Parse
                    ON ERROR GOTO SQLParse_Error
                
                
                    LOCAL SQLresult AS LONG
                    LOCAL hSlowThread AS LONG
                    LOCAL hFastThread AS LONG
                
                    LOCAL ThreadIDSlow AS LONG
                    LOCAL ThreadIDFast AS LONG
                
                    SQLHit = 0
                    THREAD CREATE SQLParse_Slow(500) TO hSlowThread
                    THREAD CREATE SQLParse_Fast(500) TO hFastThread
                
                    DO WHILE SQLHit = 0
                        SLEEP 1
                    LOOP
                
                    IF SQLHit = 1 THEN
                        ' _Fast provides results: close slow also
                        THREAD CLOSE hSlowThread TO SQLresult
                        THREAD CLOSE hFastThread TO SQLresult
                
                    ELSEIF SQLHit = 2 THEN
                        ' fast provides no resuls: wait for slow
                        THREAD CLOSE hFastThread TO SQLresult
                
                        DO WHILE SQLHit < 3
                            SLEEP 1
                        LOOP
                
                        THREAD CLOSE hSlowThread TO SQLresult
                        IF SQLHit = 3 THEN
                            ' we've got result
                        ELSEIF SQLHit = 4 THEN
                            CALL ERRORHandle
                        END IF
                
                    ELSEIF SQLHit = 3 THEN
                        ' Slow finished before Fast : ??
                        ' Yet result, so close both
                        THREAD CLOSE hSlowThread TO SQLresult
                        THREAD CLOSE hFastThread TO SQLresult
                
                    ELSEIF SQLHit = 4 THEN
                        ' Slow finished before Fast : ??
                        ' Wait for fast
                        THREAD CLOSE hSlowThread TO SQLresult
                
                        DO WHILE SQLHit <> 1 AND SQLHit <> 2
                            SLEEP 1
                        LOOP
                        THREAD CLOSE hFastThread TO SQLresult
                
                        IF SQLHit = 1 THEN
                            ' we've got a result
                        ELSEIF SQLHit = 2 THEN
                            CALL ErrorHandle
                        END IF
                    ELSE
                        ' safety sake
                        THREAD CLOSE hSlowThread TO SQLresult
                        THREAD CLOSE hFastThread TO SQLresult
                    END IF
                    
                    MSGBOX OutputString
                
                    EXIT SUB
                
                SQLParse_ERROR:
                    PRINT #1, "Error in SQL Parse"
                
                    CALL ErrorHandle
                    EXIT SUB
                
                END SUB
                
                
                FUNCTION SQLParse_Fast(BYVAL x AS LONG) AS LONG
                
                    IF INSTR(1, QString, "test") <> 0 THEN
                        OutputString = "FAST"
                    END IF
                    SLEEP 50
                
                END FUNCTION
                
                
                FUNCTION SQLParse_Slow(BYVAL x AS LONG) AS LONG
                
                    IF INSTR(1, QString, "string") <> 0 THEN
                        OutputString = "SLOW"
                    END IF
                    SLEEP 5000
                
                END FUNCTION
                
                SUB ErrorHandle
                    OutputString = "error"
                END SUB

                Then one more thing (but maybe these collide with the error above), how do I NOT provide a global to make sure I know when one or the other is finished.
                Is it just the use of two variables (i.e. SQLHit1 and SQLHit2) where I use just one variable now. Just that simple, or isn't that what you mean.

                Hope you can help

                Jeroen


                ------------------

                Comment


                • #9
                  > I changed the threadID to 500

                  To be clear, the value that you pass to your thread function is not in any way a "thread ID", unless that is what you choose to use the value for. That parameter is provided so that you can, if you want to, pass a value to the thread as it starts up. The value that you choose will have no effect on the thread creation process. Think of it as a "generic parameter" that you can use for anything you want. The term "thread ID" has a specific meaning in Windows programming, and you should not confuse that THREAD CREATE parameter with a thread ID.

                  >So what am I doing wrong in this code
                  >
                  > #COMPILE DLL "C:\MT_TEST.exe"

                  That's your problem right there. You're telling PowerBASIC to create a DLL with the extension EXE. Which is it?

                  -- Eric

                  ------------------
                  Perfect Sync: Perfect Sync Development Tools
                  Email: mailto:[email protected][email protected]</A>
                  "Not my circus, not my monkeys."

                  Comment


                  • #10
                    OK, too easy. I changed it, it works. Thanks. To go on where I started:

                    Let's add one more sub

                    Code:
                    SUB SQL_1(SQLST AS STRING)
                    
                        LOCAL result&
                        ' SQL uitvoeren op de index
                        result& = SQL_Stmt(%IMMEDIATE, SQLSt)
                        IF result& = %SQL_NO_DATA THEN
                            SQLST = "no data in RS!"
                        ELSEIF result& <> %SUCCESS AND result& <> %SUCCESS_WITH_INFO THEN
                            SQLST = SQL_ErrorQuickAll
                        ELSE
                            SQLST = ""
                        END IF
                    
                    END SUB
                    When I add a call to after I closed my threads instead of the messagebox

                    Code:
                        LOCAL SQLST AS STRING
                        SQLST = "Select RecordCounter Where recnr = 1"
                        CALL SQL_1(SQLST)
                    I get the error: "Statement too complex" on the line "IF result& = %SQL_NO_DATA THEN"
                    In my real dll, I also get this error about 10 lines down.

                    As I mentioned to Darryl, I only get this error right on or just after a line having to do with SQL Tools.
                    Darrayl nicely explained that it cannot be SQL Tools but it has to do with it evidently.
                    PB apparently has problems dealing with SQL Tools in case of multi-threading. And this is exactly what I want to do!

                    Hope you can help a little more

                    Thanks in advance

                    Jeroen



                    ------------------

                    Comment


                    • #11
                      > how do I NOT provide a global to make
                      > sure I know when one or the other is
                      > finished.

                      Here's the problem with using a GLOBAL STRING variable. As you probably know, multi-tasking on a single-processor computer is an illusion. The Windows operating system really gives a "time slice" to each thread, one at a time, so no two threads (or programs) are really running at any given instant. It happens so fast that we humans think that everything is happening at once, but it's not.

                      The operating system can interrupt a thread at any instant, even "inside" a PowerBASIC statement or function, and give control to another thread. So PB might literally be in the middle of changing a string variable to a new value when another thread gets control and decides to change that same string variable... and you end up with junk, at best, or a GPF, at worst.

                      Working with threads requires you to think in different ways. Let's say you have 10 threads that are all running, and you want to find out which one finishes first. You could create a ten-element global array of variables, and have each thread use a different element. In fact, that would be a great use for the "generic parameter"... You would pass "1" to the first THREAD CREATE, to tell it to use array element number 1, and pass "2" to the second THREAD CREATE, and so on. Then your "main" thread could constantly use ARRAY SCAN (or a FOR/NEXT loop) to check for a thread that has finished.

                      Lots of variations on that basic idea are possible.

                      If you really want to use the same variable -- which is often the case -- then you must use things call "synchronization objects" to make sure that the threads respect each other properly. That's a whole new topic, and more than I can get into right now. Search the BBS for "critical sections" and you should find some code that demonstrates the general idea.

                      Threads are incredibly powerful, but they require you to think in new ways. One piece of advice: when you're just getting started, respect what other people have figured out. If you look at a piece of sample code and think "gee, why go to all that trouble, all you have to do is this..." then you're going to fall into a trap. When you first start working with threads it's tempting to try to do things "the easy way", but unless you do them "the right way" your program will eventually fail.

                      -- Eric




                      ------------------
                      Perfect Sync: Perfect Sync Development Tools
                      Email: mailto:[email protected][email protected]</A>
                      "Not my circus, not my monkeys."

                      Comment


                      • #12
                        Hi Eric, thanks a lot (again).

                        OK, why aren't you writing a proper manual about multi-threading. This is the best practical advice I've gotten so far.
                        Anyway, I changed the threadID to 500, just to make a difference. I changed my subs to functions.

                        So now it compiles but provides the error that this isn't a valid WIN32 application.
                        So what am I doing wrong in this code

                        Code:
                        #COMPILE DLL "C:\MT_TEST.exe"
                        $INCLUDE "C:\Sparker\SQLTools\SQL_PRO2.INC"
                        $INCLUDE "C:\Sparker\SQLTools\WIN32API.INC"
                        
                        GLOBAL QString AS STRING
                        GLOBAL SQLHit AS LONG
                        GLOBAL OutputString AS STRING
                        
                        FUNCTION PBMAIN() AS LONG
                            
                            QString = "teststring"
                            CALL SQL_Parse
                        
                        END FUNCTION
                        
                        SUB SQL_Parse
                            ON ERROR GOTO SQLParse_Error
                        
                        
                            LOCAL SQLresult AS LONG
                            LOCAL hSlowThread AS LONG
                            LOCAL hFastThread AS LONG
                        
                            LOCAL ThreadIDSlow AS LONG
                            LOCAL ThreadIDFast AS LONG
                        
                            SQLHit = 0
                            THREAD CREATE SQLParse_Slow(500) TO hSlowThread
                            THREAD CREATE SQLParse_Fast(500) TO hFastThread
                        
                            DO WHILE SQLHit = 0
                                SLEEP 1
                            LOOP
                        
                            IF SQLHit = 1 THEN
                                ' _Fast provides results: close slow also
                                THREAD CLOSE hSlowThread TO SQLresult
                                THREAD CLOSE hFastThread TO SQLresult
                        
                            ELSEIF SQLHit = 2 THEN
                                ' fast provides no resuls: wait for slow
                                THREAD CLOSE hFastThread TO SQLresult
                        
                                DO WHILE SQLHit < 3
                                    SLEEP 1
                                LOOP
                        
                                THREAD CLOSE hSlowThread TO SQLresult
                                IF SQLHit = 3 THEN
                                    ' we've got result
                                ELSEIF SQLHit = 4 THEN
                                    CALL ERRORHandle
                                END IF
                        
                            ELSEIF SQLHit = 3 THEN
                                ' Slow finished before Fast : ??
                                ' Yet result, so close both
                                THREAD CLOSE hSlowThread TO SQLresult
                                THREAD CLOSE hFastThread TO SQLresult
                        
                            ELSEIF SQLHit = 4 THEN
                                ' Slow finished before Fast : ??
                                ' Wait for fast
                                THREAD CLOSE hSlowThread TO SQLresult
                        
                                DO WHILE SQLHit <> 1 AND SQLHit <> 2
                                    SLEEP 1
                                LOOP
                                THREAD CLOSE hFastThread TO SQLresult
                        
                                IF SQLHit = 1 THEN
                                    ' we've got a result
                                ELSEIF SQLHit = 2 THEN
                                    CALL ErrorHandle
                                END IF
                            ELSE
                                ' safety sake
                                THREAD CLOSE hSlowThread TO SQLresult
                                THREAD CLOSE hFastThread TO SQLresult
                            END IF
                            
                            MSGBOX OutputString
                        
                            EXIT SUB
                        
                        SQLParse_ERROR:
                            PRINT #1, "Error in SQL Parse"
                        
                            CALL ErrorHandle
                            EXIT SUB
                        
                        END SUB
                        
                        
                        FUNCTION SQLParse_Fast(BYVAL x AS LONG) AS LONG
                        
                            IF INSTR(1, QString, "test") <> 0 THEN
                                OutputString = "FAST"
                            END IF
                            SLEEP 50
                        
                        END FUNCTION
                        
                        
                        FUNCTION SQLParse_Slow(BYVAL x AS LONG) AS LONG
                        
                            IF INSTR(1, QString, "string") <> 0 THEN
                                OutputString = "SLOW"
                            END IF
                            SLEEP 5000
                        
                        END FUNCTION
                        
                        SUB ErrorHandle
                            OutputString = "error"
                        END SUB

                        Then one more thing (but maybe these collide with the error above), how do I NOT provide a global to make sure I know when one or the other is finished.
                        Is it just the use of two variables (i.e. SQLHit1 and SQLHit2) where I use just one variable now. Just that simple, or isn't that what you mean.

                        Hope you can help

                        Jeroen

                        ------------------

                        Comment


                        • #13
                          Jeroen --

                          You posted a new question while I was composing my last answer, so things are a little out of order here...

                          > PB apparently has problems dealing with
                          > SQL Tools in case of multi-threading. And
                          > this is exactly what I want to do!

                          The problem is not with SQL Tools, per se. After you gave us permission (by email) I forwarded your code to PB support, and we'll see what they have to say...

                          -- Eric


                          ------------------
                          Perfect Sync: Perfect Sync Development Tools
                          Email: mailto:[email protected][email protected]</A>
                          "Not my circus, not my monkeys."

                          Comment


                          • #14
                            That's what Darryl said, and would do. Funny thing is, I search the forum on this error and got 2 results.
                            Both instances adviced 'strip the code down to locate the problem', so I did.
                            And both instances resulted in : let's send the code to PB, to be forwarded to R&D (which will be the next step).

                            Not to be too critical being a newbee to multi-threading: but we never hear from it again (at least not on the forum).
                            Is this a known problem in PB because it would really help people like myself trying to learn multi-threading (which is hard enough), to get back the results.

                            Funny thing is, SQL Tools and PB never crash and really work great. We're trying to do sort of parallel processing data retrieval and bumped into multi-tasking. (I'll keep you updated when it's done. Almost there...)
                            So I asked a question, got a result, build it into my working code and got this error.


                            One more question and then I'll have to rest to wait for the response of PowerBASIC:
                            Where can I find a good start (really starting from scratch) on multi-threading. It seems quite tricky.


                            Greetings,
                            Jeroen

                            ------------------


                            [This message has been edited by jeroen brouwers (edited October 30, 2000).]

                            Comment


                            • #15
                              Jeroen --

                              I played around with your code for quite a while, and it appears that the repeated use of THREAD CLOSE is causing the erroneous "statement too complex" error.

                              If you look closely at your code in the IF SQLHit =... block, you will see that you are using THREAD CLOSE over and over in many different places, once after each THEN line. All you really need to do is place the two THREAD CLOSE statements (one for fast and one for slow) after the end of that IF-block. Get rid of all of the THREAD CLOSE statements inside the IF-block. Do that, and the compilation problem will disappear.

                              -- Eric


                              ------------------
                              Perfect Sync: Perfect Sync Development Tools
                              Email: mailto:[email protected][email protected]</A>
                              "Not my circus, not my monkeys."

                              Comment


                              • #16
                                Eric, thank you again.
                                This seems to be the problem. Both my test version as the large project seem to be working!
                                Gonna do some more tests, but this is great! Add it to the manual, I guess.

                                You said you owed me one, well not anymore! Thanks a lot

                                Jeroen

                                ------------------

                                Comment


                                • #17
                                  Hi again,
                                  Just one question. What we're basically doing is activating 2 ways of getting data from a database. One is thorough but slow and the other one is fast but sometimes incomplete (i.e. provides no results).
                                  Therefore, multi-threading seems like a good idea: start them both, if the fast parse provides result, OK. If it doesn't, the slow parse has already started so the program can wait for the results.

                                  Yet, how does SQL Tools handle this? Or, I should say, do I need different statementnumbers and maybe even different database numbers for the two parses or can I just leave as it was, just using SQL_STMT.
                                  Some thoughts on this would be appreciated because this is (quite logical) not something that is in the help file (at least, I didn't find it).

                                  Sincerely
                                  Jeroen

                                  ------------------

                                  Comment


                                  • #18
                                    Folks, the "statement too complex" compile-time error appears to be some kind of parsing problem with the compiler itself.

                                    As Eric pointed out, the code that produced this error was not "ideal" ( ), but the issue has been raised with R&D who will no doubt sort it out for the next update to the compiler.



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

                                    Comment


                                    • #19
                                      > how does SQL Tools handle this? Or, I should say,
                                      > do I need different statementnumbers and maybe even
                                      > different database numbers for the two parses

                                      SQL Tools Pro is thread safe. In fact, the it contains a special function (SQL_Thread) to help you sort out which errors are generated by which thread (among other things). The SQL Tools Help File covers multi-threading issues in the section titled "Multi-Threaded Programs".

                                      If you want two different SQL statements to be executing at the same time, then you would definitely need to use two different statement numbers. (Think of it as having two files open... you can't use the same file number.) You could probably use the same database connection (i.e. the same database number) but not all database drivers allow "concurrent statements", so if you need your program to be 100% ODBC compliant, to work with any ODBC database, it would be safer to use two different statement numbers. If the database that you are using does support concurrent statements, and you don't intend to use the program with other database drivers, then you could use SQL_OpenDatabase once, and then use two different statement numbers with that one connection.

                                      -- Eric


                                      ------------------
                                      Perfect Sync: Perfect Sync Development Tools
                                      Email: mailto:[email protected][email protected]tsync.com</A>
                                      "Not my circus, not my monkeys."

                                      Comment


                                      • #20
                                        Wow, this is really going somewhere!

                                        Lance: thanks, I'm curious on the fix. If you have it, please make a / some simple and 'ideal' test to show how it works.

                                        Eric, the Help file is VERY usefull, great. Apparently I overlooked this one, because this is exactly what I was looking for.
                                        It means I have to add / rewrite some things but thats no problem. Thanks again for all the efforts!

                                        Greetings
                                        jeroen



                                        ------------------

                                        Comment

                                        Working...
                                        X