Announcement

Collapse
No announcement yet.

Messagebox in separate thread

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

  • Michael Mattias
    replied
    This implies that synchronisation techniques are required at all times [in multi-thread programs]
    You know, it really does 'make my day' when one or more persons 'see the light' on one of these otherwise esoteric things about which I often post.

    Thank you for letting me know.

    MCM

    Leave a comment:


  • Mike Doty
    replied
    Win32 Message box in the background

    Code:
    DECLARE FUNCTION MessageBox LIB "USER32.DLL" ALIAS "MessageBoxA" _
                   (BYVAL hWnd           AS DWORD,     _
                        lpText           AS ASCIIZ,    _
                        lpCaption        AS ASCIIZ, _
                        BYVAL dwType     AS DWORD) AS LONG
    TYPE MyUDT
      hWnd       AS DWORD
      lpText     AS ASCIIZ * 128
      lpCaption  AS ASCIIZ * 128
      dwType     AS DWORD
    END TYPE
    FUNCTION PBMAIN&
      mb 0,"How now brown cow","Title", %MB_ICONERROR
      ? "Click to exit"
    END FUNCTION
    SUB MB(hWnd AS DWORD, lpText AS ASCIIZ,lpCaption AS ASCIIZ,dwType AS DWORD)
      LOCAL x AS MyUDT, hThread AS DWORD
      x.hWnd       = hWnd
      x.lpText     = lpText
      x.lpCaption  = lpCaption
      x.dwType     = dwType
      THREAD CREATE MessageBoxThread(VARPTR(x)) TO hThread???
      SLEEP 50
      THREAD CLOSE hThread??? TO hThread???
    END SUB
    THREAD FUNCTION MessageBoxThread(BYVAL y AS DWORD) AS DWORD
      LOCAL x  AS MyUDT POINTER
      LOCAL hWnd       AS DWORD
      LOCAL lpText     AS ASCIIZ * 128
      LOCAL lpCaption  AS ASCIIZ * 128
      LOCAL dwType     AS DWORD
      x = y
      MessageBox @x.hWnd,@x.lpText,@x.lpCaption,@x.dwType
    END FUNCTION
    Last edited by Mike Doty; 19 Oct 2009, 05:05 PM.

    Leave a comment:


  • Mike Doty
    replied
    Mike, thank you for the example, but i think this is not the equivalent of the WinApi Messagebox.
    Just change the line with ? to whatever you want.

    Leave a comment:


  • Arie Verheul
    replied
    Mike, thank you for the example, but i think this is not the equivalent of the WinApi Messagebox.
    The concerns that were brought forward were not about forwarding a string to the screen,
    but rather about properly reading the return value by the main program when one of the buttons is clicked.

    Michael, thanks for your reply.
    It is clear to me that any operation that involves more than one instruction may be interrupted
    by thread switching. From Pauls reply i learned that the operation A=B involves also two instructions.

    Edwin, thanks. I will try that.

    Paul, thanks. Your reply is very clear: the alignment issue is not present in PB.
    But on the downside, the operation A = B does not involve one instruction, as i supposed, but two,
    and may therefore be interrupted by thread switching.

    Therefore it may be concluded that a 32 bit variable is not guaranteed put in place in one single
    operation, as i supposed. This implies that synchronisation techniques are required at all times.

    Arie Verheul

    Leave a comment:


  • Edwin Knoppert
    replied
    Sleep may not help you here.
    When a computer is severely in use it may not even execute the thread before the end of sleep call.
    To solve that i ever did a similar thing, i passed allocated memory instead, the thread deletes the memory.

    You see, using threads is not that simple.
    You must guarantee for several cpu types and scenario's like memory hog and such.

    Leave a comment:


  • Mike Doty
    replied
    This one supports style and title

    Code:
    TYPE MyUDT
      txt      AS STRING * 128
      MyStyle  AS INTEGER
      title    AS STRING * 128
    END TYPE
     
    FUNCTION PBMAIN&
      LOCAL z AS ASCIIZ * 128
      LOCAL x AS LONG
      mb "How now brown cow", %MB_ICONERROR, "Title"
      ? "Click to exit"
    END FUNCTION
     
    SUB MB(txt AS STRING, STYLE AS INTEGER, Title AS STRING)
      LOCAL x AS MyUDT, hThread AS DWORD
      x.txt = txt
      x.MyStyle = STYLE
      x.Title = Title
      THREAD CREATE MessageBoxThread(VARPTR(x)) TO hThread???
      SLEEP 50
      THREAD CLOSE hThread??? TO hThread???
    END SUB
     
    THREAD FUNCTION MessageBoxThread(BYVAL y AS DWORD) AS DWORD
      LOCAL x  AS MyUDT POINTER
      x = y
      LOCAL txt   AS STRING
      LOCAL MyStyle AS INTEGER
      LOCAL Title AS STRING
      
      txt       = @x.txt
      MyStyle   = @x.MyStyle
      title     = @x.title
      ? txt,MyStyle,title
    END FUNCTION

    Leave a comment:


  • Mike Doty
    replied
    No global

    Code:
    FUNCTION PBMAIN&
      LOCAL z AS ASCIIZ * 128
      MB "No global"
      SLEEP 3000
    END FUNCTION
    SUB MB(z AS ASCIIZ)
      LOCAL x AS DWORD, hThread AS DWORD
      x = VARPTR(z)
      THREAD CREATE MessageBoxThread(x) TO hThread
      SLEEP 50
      THREAD CLOSE hThread TO hThread
    END SUB
    THREAD FUNCTION MessageBoxThread(BYVAL y AS DWORD) AS DWORD
      LOCAL z  AS ASCIIZ * 128
      ? PEEK$(y,128)
    END FUNCTION
    Last edited by Mike Doty; 19 Oct 2009, 04:08 PM. Reason: Placed "No global" in the call to eliminate another line

    Leave a comment:


  • Paul Dixon
    replied
    Arie,
    all PB declared 32 bit variables are aligned. All smaller variables are also considered aligned, although not on 32-bit boundaries they still exisist entirely within a single 4-byte aligned block of memory.
    You can force them to be unaligned, e.g. by accessing them with pointers and reading/writing them from/to odd addresses but the default condition is to have them aligned.

    The CPU will access all fully aligned data indivisibly. Be careful with 64 bit data (QUADs, DOUBLEs) and EXTs the compiler does not fully align them automatically. Quads need to be aligned on 8 byte boundaries and are only 4-byte aligned by the compiler.


    For synchronisation purposes, it doesn't matter whether a variable is aligned or not. What matters is that the access of that variable needs to be indivisible.
    With certain ASM instructions you know the instruction is indivisible but it's more difficult to determine that with a compiled instruction.
    Tom's example of A=B, when compiled actually takes 2 opcodes so it is not indivisible unless one (not both!) of the variables are register variables.

    The XCGH opcode which will exchange a register and a memory variable is always indivisible as are a few system instructions.
    Using ASM you can specify certain other instructions to be indivisible by using the LOCK prefix.

    It was so much easier in the good old days when you simply used !CLI to stop interrupts until you were finished.

    Paul.

    Leave a comment:


  • Edwin Knoppert
    replied
    >However if this can be solved by aligning the variable, no problem, how is that done?
    I believe that in the newer PB versions, global variables are aligned already.
    You have to verify this.

    If not you can create a global string of 7 bytes and calculate the correct offset.
    Global s as String * 7
    Global p as Dword ptr
    p = varptr( s )
    what is the address? / 4... and so on.
    (you'll figure out a fine divide or mod function )

    Leave a comment:


  • Michael Mattias
    replied
    >Totally agree, perhaps you should do an update to your much quoted 2008 demo

    You know, I thought about qualifying that "general rule" statement at the time, because I know I do this often. But I said, "nah, it's not necessary."

    For me it is one consistent exception... I always do this in real life . although not necessarily in demo life.

    MCM

    Leave a comment:


  • Michael Mattias
    replied
    Or conversely, how small should a variable be to make sure that it is transferred in one single operation ?
    If you mean "atomically" by the CPU, you can't. To ensure 'no thread switch during operation' you need to use one of the Interlockedxxxx functions or a synchronization object.

    Note that a PB statement calling the Interlocked functions such as...
    Code:
       InterlockedExchange     g_intvar,   g_intVar + 10
    .. is not atomic, as multiple instructions are required to calculate the value of the expression 'g_intvar + 10'

    MCM

    Leave a comment:


  • Mike Doty
    replied
    Showed polled, non-polled, crititical section, now this.
    I thought you just wanted to display a message box in another thread?
    Code:
    GLOBAL gs AS STRING
    FUNCTION PBMAIN&
      MB "one"
      MB "two
      SLEEP 2000
    END FUNCTION
    SUB MB(s AS STRING)
      gs=s
      THREAD CREATE MessageBoxThread(x???) TO hThread???
      SLEEP 50
      THREAD CLOSE hThread??? TO hThread???
    END SUB
    THREAD FUNCTION MessageBoxThread(BYVAL y AS DWORD) AS DWORD
      ? gs
    END FUNCTION
    Last edited by Mike Doty; 19 Oct 2009, 03:04 PM. Reason: VARPTR wasn't needed

    Leave a comment:


  • Arie Verheul
    replied
    Thanks all for your comment so far. Many different views were brought forward,
    but it would be great if this thread could end with a conclusive result.

    While reading on the matter i got the impression that only the technique using the
    WinApi CriticalSection functions enjoys broad support. See for example Kev Peel's post at:


    But as was brought forward both by me and by Edwin Knoppert, this seems far too complex for
    this simple purpose. There must be a simpler way, and if it didn't exist it should be invented.

    It seems important to obtain clarity about the issue how a 32 bit variable is moved to memory.
    In my ignorance i supposed that there is only one possible way: all 32 bits at the time.
    In that case there would never be a synchronisation issue with a 32 bit variable.
    Tom Hanlin supports this view, but has general doubts.
    Edwin Knoppert and John Petty however suppose that this is only true if the variable is properly aligned.

    Does this really mean that the processor might move a part of a 32 bit variable to memory, go away to do
    other things, and come back later for the remainder of the variable? Seems really weird to me.
    However if this can be solved by aligning the variable, no problem, how is that done?

    Or conversely, how small should a variable be to make sure that it is transferred in one single operation ?

    Arie Verheul

    Leave a comment:


  • John Petty
    replied
    Originally posted by Michael Mattias View Post
    "As a general rule" you would never call WFSO from your primary GUI thread while you still have a screen up.
    MCM
    Totally agree, perhaps you should do an update to your much quoted 2008 demo

    Leave a comment:


  • Michael Mattias
    replied
    I suspect this is more or less equivalent to the WaitForSingleObject approach, with the difference
    that it is not tested all the time, but only when i need to know this.
    Not the same at all. WFSO does not return until the event (thread handle) is signalled or the timeout period is reached. THREAD STATUS gets the exit code of the thread and returns.

    WFSO could never work as a 'drop in replacement' for a THREAD STATUS.....IF.. EXIT ...END IF test... you'd never get to the 'END IF'

    "As a general rule" you would never call WFSO from your primary GUI thread while you still have a screen up.

    MCM

    Leave a comment:


  • Arie Verheul
    replied
    I had to spend most of this sunday on tidying up the garden for the winter, and usually that helps.
    At least i think it did.

    In my example the thread finishes immediately after a button on the messagebox is clicked.
    This means that if i test with the Thread Status function if the thread has finished,
    and find that the thread has finished indeed, i can after that always read safely any variable.

    I suspect this is more or less equivalent to the WaitForSingleObject approach, with the difference
    that it is not tested all the time, but only when i need to know this.
    Would this be an acceptable approach for this simple case?

    In the example below i implemented this change. For the convenience of PBWin users i eliminated the console.

    Arie Verheul



    Code:
     
    #Console Off                    ' Remove for PBWIN
    #Include "win32api.inc"
     
    Function PBMain () As Long
     
        Dim MsgText  As Global Asciiz*60
        Dim Response As Global Long
     
        Local hThread       As Dword
        Local ThreadVar     As Dword
        Local hWnd          As Dword
        Local FontHndl      As Dword
        Local I,J,K,L       As Long
        Local ThreadStatus  As Long
        Local ThreadStarted As Long
        
        '-------------------------------------------------------------
        ' Set up graphic window
     
        Graphic Window "Messagebox in thread", 100,100,300,200 To hWnd
        Graphic Attach hWnd,0
        Graphic Color %White,%Black
        Graphic Clear
        
        Font New "Courier New",12 To FontHndl
        Graphic Set Font FontHndl
        '-------------------------------------------------------------
        
        MsgText       = "Just say so if you want to stop when this set is finished"
        
        ThreadStarted = 0
     
        Do
            For J = 2 To 9
                For I = 1 To 10
                    K = I * J
                    Graphic Print Using$( Space$(8) + "## x # = ##",I,J,K)
                    Sleep 100
                Next
                Sleep 1000
                Graphic Clear
                If IsWindow(hWnd) = 0 Then Exit Function    ' End program if window was closed
            Next
     
            Incr L
            
            '----------------------------------------------------------------------------------
            If L = 1 Then                                   ' Show message box
                
                Thread Create Message (ThreadVar) To hThread
                Threadstarted = -1                          ' Set flag that messagebox thread was started
            End If
            
            '----------------------------------------------------------------------------------
    	' This is to test if thread is still running or has finished
     
            If ThreadStarted Then                           ' Test if thread has finished
                Thread Status hThread To ThreadStatus
                If ThreadStatus = 259 Then Iterate Loop     ' 259 corresponds to running thread
            End If
            '----------------------------------------------------------------------------------
     
        Loop Until Response = 6
     
    End Function
     
    '------------------------------------------------------------------------------------------
    ' Message box thread function
     
    Thread Function Message (ByVal ThreadVar As Dword)  ' ThreadVar is a dummy variable
     
        MessageBox 0, MsgText, "Test Message Box" , 4 To Response
     
    End Function
    '------------------------------------------------------------------------------------------

    Leave a comment:


  • Mel Bishop
    replied
    ...we...got a little off the subject... The OP asked about MessageBoxes [and] an answer was given...
    I agree. I posted a comment totally in passing and here we are.

    Not that anybody will listen but I think it's time this thread died a quiet, (un)dignified death.

    Leave a comment:


  • John Petty
    replied
    Originally posted by Tom Hanlin View Post
    I think you're safe in handling a global LONG or DWORD value. That's almost guaranteed to take just one instruction, if you're doing something simple like a LET A=B sort of thing. BUT.
    Only true if the long is correctly aligned thus my restriction that it is always true if only used as a True/False flag. There are of course many very fast Interlocked calls that can be used for common situations

    That's a big BUT.

    Thread-safe programming can be monstrously complicated to get exactly perfect, perhaps because we're generally trained to think of things working in sequential order, and threads are asynchronous. And there's the serious problem that a thread error may only appear "at random", when the moon is full and two people accidentally read their in-boxes at the same microsecond.

    I'd like to say, "don't". But there's no point in avoiding it, the ability to spawn a new thread is unbelievably powerful. Just try not to cut off all your fingers with that knife. Read up on thread programming, and be careful out there.
    Yes it takes some reading but in PB is well supported and apart from multiple threads transferring data between each other are relatively simple.
    Unfortunately the most often quoted example in source code ties itself in knots because it is unneccasarily complicated so the author then uses more complicated code to fix the problem he created, I quote from the program
    Code:
     ' I had to use a string ptr here instead of CONTROL GET TEXT because the calling thread was in a wait
     ' state (WaitForSingleObject) and apparently (undocumented but not reasonably) CONTROL GET TEXT does
     ' "something" which must execute in the context of the same thread (suspended) as the dialog.
     ' Apparently (that means also not documented), DIALOG GET USER does not need to execute anything in the
     ' context of the thread in which the dialog was created.
    Nearly all the complicated code goes away if the calling main thread is not itself suspended with a totally unneed WFSO immediately after the thread creation. In fact the program then uses a timer to update the screen which really defeats the purpose of a worker thread.
    Now he claims WFSO takes zero time, I assume he is a believer in string theory and his programs work in some higher dimension, hopefully he will soon demonstrate a program that finishes before it starts

    Leave a comment:


  • Michael Mattias
    replied
    If this were about software for rocket launching, or the stock exchange, i would
    have been much more careful. But as it is in the given case about a simple
    messagebox
    That's one way to look at it.

    But as Mr. Hanlin states, multithreaded programming can be "monstrously complex." The chance to learn the proper techniques in a *simple* application like this demo is a blessing.

    Or perhaps you would prefer to learn it with a factory production line down whilst your client's attorney is multiplying total downtime by $5000 per hour?

    MCM

    Leave a comment:


  • Tom Hanlin
    replied
    I think you're safe in handling a global LONG or DWORD value. That's almost guaranteed to take just one instruction, if you're doing something simple like a LET A=B sort of thing. BUT.

    That's a big BUT.

    Thread-safe programming can be monstrously complicated to get exactly perfect, perhaps because we're generally trained to think of things working in sequential order, and threads are asynchronous. And there's the serious problem that a thread error may only appear "at random", when the moon is full and two people accidentally read their in-boxes at the same microsecond.

    I'd like to say, "don't". But there's no point in avoiding it, the ability to spawn a new thread is unbelievably powerful. Just try not to cut off all your fingers with that knife. Read up on thread programming, and be careful out there.

    Leave a comment:

Working...
X
😀
🥰
🤢
😎
😡
👍
👎