Announcement

Collapse
No announcement yet.

Threads and checking their status

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

  • Threads and checking their status

    Threads are initialized and started asynchronously, so it is wise to give the operating system a small amount of time to perform thread initialization before using the THREADCOUNT function to monitor the thread.
    How much time? 1ms? 2 ms? 16ms?????

    Is there a function that checks and tells if started? (my best guess is Thread STATUS)

    I have also been looking at how to pass parameters, but all I can find (both PB and API) is that creating a thread takes only 1 and ONLY 1 parameter, so other ideas have to come into play (and GLOBALS are not an option, unless I misread the whole idea of "Context Switching"???)
    Engineer's Motto: If it aint broke take it apart and fix it

    "If at 1st you don't succeed... call it version 1.0"

    "Half of Programming is coding"....."The other 90% is DEBUGGING"

    "Document my code????" .... "WHYYY??? do you think they call it CODE? "

  • #2
    IMO that is not a good piece of 'general' advice.

    Once THREAD CREATE returns, the thread object exists. The thread function may have executed zero lines or or may have already reached its logical end before the calling thread gets a chance to execute the next instruction.

    Regardless, there is no need to guess how long: See the use of a 'ready event' in http://www.powerbasic.com/support/pb...ad.php?t=35619

    You signal the ready event from the thread function when, when, well, when you are "ready" for the calling thread to continue processing. Your code following WaitforSingleobject starts then.

    I usually wait only until I have copied the thread function parameters to one or more LOCAL variables.

    MCM
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      Cliff,
      the time is indeterminate. It might be a few microseconds or it might be many seconds.

      When you are restricted to passing one parameter and need to pass more than one item of information then you need to create a UDT which contains all the information then pass that UDT as the single parameter.
      Often you might be restricted to passing a single LONG parameter in which case you would pass the address of the UDT.

      You can always include a flag in the UDT which the thread sets when it's started which indicates to the calling code that the thread is running. Either that or use WaitForSingleObject.

      Paul.
      Last edited by Paul Dixon; 11 Dec 2008, 06:52 PM.

      Comment


      • #4
        Tracking everything without a GLOBAL array would be nice.
        I'm using a couple of THREADED variables and DDT's CONTROL GET/SET USER. How to eliminate all GLOBALS?
        Second thought: A disk file could be used allowing unlimited storage. Might be fast enough with disk cache.
        Code:
        THREAD FUNCTION Threads(BYVAL ElementPassed AS LONG) AS DWORD
          LOCAL ThreadElementNumber AS LONG
          Element = ElementPassed 'element is a threaded variable
          WhatToSend
          CONTROL SET TEXT ghDlg, Buttons(ElementPassed), "Send"
          CONTROL ENABLE ghDlg, Buttons(ElementPassed)
          CONTROL GET USER ghDlg, Buttons(ElementPassed),1 TO ThreadElementNumber
          ghThread(ThreadElementNumber) = 0
        END FUNCTION
        SUB StartThread(ElementPassed AS LONG)
          LOCAL x AS LONG, result AS LONG
          FOR x = 1 TO 9 'find a thread handle
            IF ghThread(x) = 0 THEN 'find an element with 0 and
              THREAD CREATE Threads(ElementPassed) TO ghThread(x) 'selection Element assigned to ghThread(x)
              THREAD CLOSE ghThread(x) TO result
              CONTROL SET USER ghDlg, Buttons(ElementPassed), 1, x 'element number holding thread in use
              CONTROL SET TEXT ghDlg, Buttons(ElementPassed), "Thread"+ STR$(X)
              EXIT FOR
            END IF
          NEXT
          SLEEP 50
        END SUB
        Last edited by Mike Doty; 12 Dec 2008, 10:34 AM.
        The world is full of apathy, but who cares?

        Comment


        • #5
          What you have can never work as written.

          You doing this...
          Code:
          CONTROL GET USER ghDlg, Buttons(ElementPassed),1 TO ThreadElementNumber
          .. in the StartThread function, but doing this:
          Code:
          CONTROL SET USER ghDlg, Buttons(ElementPassed), 1, x 'element number holding
          .. in the thread function, with absolutely no knowledge of to what point that thread function has executed yet; i,e, has the "CONTROL SET USER" been done or not at the point you GET that value?

          Even if Button() is THREADED (code not shown) , without some kind of synchronization you are just asking - nay, begging - for some data corruption.

          MCM
          Michael Mattias
          Tal Systems (retired)
          Port Washington WI USA
          [email protected]
          http://www.talsystems.com

          Comment


          • #6
            Also, once you close your thread handle (THREAD CLOSE) , you ain't getting it back without keeping track of the THREADID so you can OpenThread to get a fresh handle.

            (Ok, so you CAN do it but I hope either A) you are handy with the DuplicateHandle() function or B) you can find the demo I wrote which does this).

            MCM
            Michael Mattias
            Tal Systems (retired)
            Port Washington WI USA
            [email protected]
            http://www.talsystems.com

            Comment


            • #7
              Although I suspect this is just some "Let's see what happens" code..
              Code:
              THREAD FUNCTION Threads(BYVAL ElementPassed AS LONG) AS DWORD
                LOCAL ThreadElementNumber AS LONG
                Element = ElementPassed 'element is a threaded variable
                WhatToSend
                CONTROL SET TEXT ghDlg, Buttons(ElementPassed), "Send"
                CONTROL ENABLE ghDlg, Buttons(ElementPassed)
                CONTROL GET USER ghDlg, Buttons(ElementPassed),1 TO ThreadElementNumber
                ghThread(ThreadElementNumber) = 0
              END FUNCTION
              ..this function will probably complete in about 200 milliseconds, even with the thread context switches being forced. Using separate threads for this purpose is a little, well, "overkill."

              MCM
              Michael Mattias
              Tal Systems (retired)
              Port Washington WI USA
              [email protected]
              http://www.talsystems.com

              Comment


              • #8
                Mike,
                Maybe "Threaded Variables" is what I need to look into, but my low-level experiments with "Non-Global" may help

                Lately I have been experimenting with each parameter essentially being the reply, and the reply to the function being if there was an error or no error.

                (Maybe a lil unorthodox but if needing multiple replies, (or using threads) and trying to be "Thread-Safe" and still not use a GLOBAL (which to my limited reading "Threaded" variables are GLOBAL but only within the thread") may be either how PB does it, or my misconstrued idea of doing the same???

                I have to admit, only tonight did my "Dim Bulb" start to glow a little when you mentioned "Threaded Variables" to possibly solve a concept of needing to share a variable, but make that variable only "Global to the local sandbox" kind of concept)
                Engineer's Motto: If it aint broke take it apart and fix it

                "If at 1st you don't succeed... call it version 1.0"

                "Half of Programming is coding"....."The other 90% is DEBUGGING"

                "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                Comment


                • #9
                  THREADED variables are essentially "THREAD STATIC" but may be accessed with a GLOBAL scope... i.e, it is PB's easy-to-use implementation of Thread Local Storage (q.v. in your Windows reference or at MSDN web site).

                  (Demo of SDK-Style TLS: Terminate Worker Threads Using Windows Events (and Using Thread Local Storage) Demo Dec 23 2005)

                  Synchronization issues are independent of variable type; synchronization is used to control "in what order" things happen when you would otherwise have no control over that... e.g, a multithreaded program, where the operating system controls which thread of execution gets a time slice in which to "do stuff."

                  Im multi-threaded programs, the use of the THREADED variable scope is an optional technique; the use of synchronization of some kind is a requirement.

                  MCM
                  Michael Mattias
                  Tal Systems (retired)
                  Port Washington WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment


                  • #10
                    I wrote a program without waitforsingleobject or the need for thread handles. It doesn't allow ending unless an array of in use threads is all zeros. When a thread has run to completion it sets an array element to zero. Critical section for updating a global.
                    Last edited by Mike Doty; 13 Dec 2008, 09:51 AM.
                    The world is full of apathy, but who cares?

                    Comment


                    • #11
                      It doesn't allow ending unless an array of in use threads is all zeros. When a thread has run to completion it sets an array element to zero.
                      Philistines!

                      Code:
                      FUNCTION Foo(N AS LONG) AS LONG
                       LOCAL hThread() AS LONG, Z AS LONG 
                         REDIM hThread (n) 
                         FOR Z = 1 TO N 
                            THREAD CREATE  threadfunction(param) TO hThread(Z) 
                         NEXT 
                         WaitForMultipleObjects  N, BYVAL VARPTR(hThread(1)), %TRUE, %INFINITE
                         MSGBOX "All thread functions have run to completion, cleaning up now" 
                         FOR Z = 1 TO N 
                            THREAD CLOSE hThread(Z) TO dummy 
                         NEXT 
                      END FUNCTION
                      MCM
                      Michael Mattias
                      Tal Systems (retired)
                      Port Washington WI USA
                      [email protected]
                      http://www.talsystems.com

                      Comment


                      • #12
                        Threads may be created at anytime unlike your example.
                        The world is full of apathy, but who cares?

                        Comment


                        • #13
                          Fine, so make hThread() GLOBAL and WFMO at the end just as shown. You said you were protecting GLOBAL vars using a CriticalSection object, just do the same with hThread() and you will be happier than a pig in slop.
                          Michael Mattias
                          Tal Systems (retired)
                          Port Washington WI USA
                          [email protected]
                          http://www.talsystems.com

                          Comment


                          • #14
                            Ok, so that's a bit brusque.

                            WFMO is a poor selection of method ("how") if you have to "do something" when the user tries to end the program and you .. well, how about an audio clip to describe that situation?

                            Oops, this extension is not a supported "attachment" type on this board so I'll have to put it on my web site:



                            MCM
                            Michael Mattias
                            Tal Systems (retired)
                            Port Washington WI USA
                            [email protected]
                            http://www.talsystems.com

                            Comment


                            • #15
                              All good things (within their own scope)

                              I found myself back to basics and checking things without threads. (Just let each sequentially happen, and then later go back to threading)

                              So far, so good (some minor curiosities about if I am reinventing the wheel getting rid of globals but I Digress this to another subject)

                              What I am now finding is, "Add a message box" and problem goes away, (both with threads and without)

                              Without a messagebox, then the problem is back.....leading me back to maybe msgbox or other time saver allows for memory to not be corrupted, or something else.

                              DEFINITELY brings me back to "Code Not Shown" and need to find a demo that I can explain so I know how to ask the question?

                              Hoping to grasp a concept soon, as all I have to lead me is compilers (C and PB) work just fine.....Interpreted (Labview and VB) bail....
                              (Results vary from test to test, and can not find a constant)

                              Give me a bit, I will find SOME sort of concept of testing.
                              Engineer's Motto: If it aint broke take it apart and fix it

                              "If at 1st you don't succeed... call it version 1.0"

                              "Half of Programming is coding"....."The other 90% is DEBUGGING"

                              "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                              Comment


                              • #16
                                MSGBOX could prevent a thread from running to completion and could
                                be serving as a message pump (if I'm not incorrect.)
                                Are you using a modeless dialog with a message pump?
                                Put a messge box as the last line in all threads and PBMAIN and see if they all appear.
                                I never place DDT code or ask for input outside the main thread.
                                Last edited by Mike Doty; 14 Dec 2008, 07:32 PM.
                                The world is full of apathy, but who cares?

                                Comment


                                • #17
                                  What I am now finding is, "Add a message box" and problem goes away, (both with threads and without)

                                  Without a messagebox, then the problem is back..
                                  With or without additional threads of execution, sounds like a synchronization or timing issue.

                                  Either the message loop provided by the modal dialog (MSGBOX) is providing a venue for a notification message to get procesesed which had not been processed without that loop, or the fact the calling function does not continue until the box is dismissed is preventing something from occurring until that happens.
                                  Michael Mattias
                                  Tal Systems (retired)
                                  Port Washington WI USA
                                  [email protected]
                                  http://www.talsystems.com

                                  Comment


                                  • #18
                                    Thats what I am figuring MCM.

                                    The deeper I got the worse it got. But then I found #DEBUG DISPLAY ON

                                    which seems to work only if I have no error handling? (If I read the Docs correctly that is)

                                    Using that, I was able to strip down some demos of the problem and think I have tracked it down after eliminating all error handling (except#DEBUG DISPLAY On) and minimizing all other code I could find with the following results
                                    DemoHardDriveInfoPassByte.bas = No Crash, no warnings
                                    DemoHardDriveInfoPassInitializedByte.bas = Untrapped Error #241 (Global memory corrupt) in Vista (If I am lucky, or I get the typical Vista close error)
                                    DemoHardDriveInfoNoDll.bas = No Errors (probably because I am Forced to pass the pointer to UDT and not a byte array)


                                    Now the DOOZY is in VB (where I am forced to pass an array of bytes to use the function is I get the following results)
                                    Compiled...XP I get the Exe Application Error.
                                    Interpreted ... XP I get the Untrapped error
                                    Compiled... Vista I get the Untrapped Error
                                    Interpreted... Vista I get the Vista Error and have to close(but only if run once (or more) and then the form/dialog gets focus so that I can edit the code)

                                    Attached should be the code I used for each Test and 2 pictures of the 2 errors I get (XP Pics, but you get similar in Vista)

                                    So I am really starting to wonder just what case of CNDS am I committing this time? (Been staring at this code toooooo lonnnnnnng for what should be such a SIMPLE subject)
                                    Attached Files
                                    Engineer's Motto: If it aint broke take it apart and fix it

                                    "If at 1st you don't succeed... call it version 1.0"

                                    "Half of Programming is coding"....."The other 90% is DEBUGGING"

                                    "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                                    Comment

                                    Working...
                                    X