Procedure and START it in 2 Threads

Great, I am glad it worked.

For others that don’t want to download the zip. I am showing the new version of @Daniel1 code.

Calling procedure (Main)

ThreadCounter       LONG(3)
ThreadQ             Queue
Thread                  SIGNED
                    END

!Button 1 press
        glo:MainThread = THREAD()
        ThreadQ.Thread= start(MyProcedure, 35000, ThreadCounter)
        ADD(ThreadQ)
        resume(ThreadQ.Thread) !probably not needed?

!ThisWindow.TakeNotify PROCEDURE(UNSIGNED NotifyCode,SIGNED Thread,LONG Parameter)

    ThreadCounter -= 1
    IF ThreadCounter > 0
        ThreadQ.Thread= start(MyProcedure, 35000, ThreadCounter)
        ADD(ThreadQ)
        resume(ThreadQ.Thread) !Probably not needed
    END

MyProcedure thread code

TimerLength             LONG(1)      !Adjust as required
FirstTime               LONG(TRUE)   ! Initialize to TRUE in the beginning of processing
EndOfFileFlag           LONG(FALSE)  ! Track if weve reached the end of the file
RecordsProcessed        LONG         ! Counter for how many records processed in each timer event
MaxRecordsPerCycle      EQUATE(1000) !Adjust as required
L                       LONG

!OF EVENT:OpenWindow
        0{prop:timer} = TimerLength !Start timer
        NOTIFY(0,glo:MainThread)  !Notify starting thread that we are open

!OF EVENT:Timer
        0{PROP:Timer} = 0               ! Disable timer while processing
        IF L >= mLoop * 10
            0{prop:text} = 'DONE! - SHOULD CLOSE NOW'
            POST(EVENT:CloseWindow)      ! Post a close window event
        ELSE
            IF FirstTime
                CLEAR(m:record)          ! Clear the record buffer
                SET(m:idKey, m:idKey)    ! Set key for the table (only once, on first event)
                FirstTime = FALSE        ! Set flag to indicate we no longer need to start from the beginning
            END
        
            IF NOT EndOfFileFlag
                ! Process X records in each timer event
                RecordsProcessed = 0
                LOOP
                    IF Access:MyTable.Next() <> Level:Benign
                        EndOfFileFlag = TRUE  ! Set the flag when no more records
                        BREAK
                    END
                ! Increment the processed counter
                    RecordsProcessed += 1
                ! Update the window's text field with progress
                    0{PROP:Text} = 'Cycle: ' & mLoop & ' Done: ' & FORMAT(L/(mLoop*10)*100,@n02) & '% - Thread: ' & THREAD() & ' Time: ' & FORMAT(CLOCK(), @t4)
                ! Exit after processing 10 records in this timer event
                    IF RecordsProcessed >= 1000
                        BREAK
                    END
                END
            END
        
            IF EndOfFileFlag
                L += 1                   ! Increment when all records are processed
                ! Reset flags to allow the process to start again if needed
                EndOfFileFlag = FALSE     ! Reset the end of file flag
                FirstTime = TRUE          ! Set FirstTime to TRUE if we want to reset the table for the next cycle
            END
            0{PROP:Timer} = TimerLength  ! Re-enable the timer
        END
2 Likes

You need 2 commas, the POST(, Thread,1) is the 3rd parameter. You probably want to add a “,1” as the 4th parameter to place your Close event 1st in the message queue.

The Clarion Help is really good and always worth a quick read when code is not working.

POST( event [,control] [,thread] [,position] )

2 Likes

@CarlBarnes Thanks but it don’t work :frowning:
The code is inside Window.TakeEvent procedure and it does not send that POST to window because it is “locked” until previous dialog/thread is not cloded.
If the code is not inside TakeEvent, then it is not executed at all.
You can check sample if you want (it is here).
@Mark_Sarson wrote another sample of how to deal with database records - now I need to figure out how to use their code for other processes like backup procedure, export to Excel etc.

Once you find what you need, I agree that the help is very good.

I find the Clarion help to work best when I already know the answer (and where to find it). But I know there have been plenty of frustrated people looking for help in the forums because they can’t find what they’re looking for.

I used two quotes in my example Procedure and START it in 2 Threads - #17 by RchdR but it disappears on the forum here.

I dont think the [,control] is “optional”, I think it needs to be just left blank eg.

POST( event , [control] [,thread] [,position] )

I think POST is a RTL wrapper of sorts for this API which also doesnt have wParam or lParam as optional, but 0 aka null is still a valid value and the Post might have its procedure parameters defined as ‘=0’ for default values.
PostMessageA function (winuser.h) - Win32 apps | Microsoft Learn

POST() is for events within a Clarion ACCEPT loop.

PostMessage is for the kind of stuff you can get with subclassing.

2 Likes

Yeah but I found one or two clarion functions where it needed a double comma as it could not be used optionally, hence the “, [param] ,” and not “[, param],”

When I get a chance I’ll go back through my code to highlight them, but it was on a win10 Pro dev machine, but I thought Post was one of them, hence why I said what I said.

Dont know if these clarion functions were being shimmed either…
Shim (computing) - Wikipedia

sounds like looking up a word in a dictionary to find out how to spell it :grinning:

1 Like

Thanks, but it does not work, too. I presume it is because it just can not break the Window.TakeEvent utnil previous window close.

All I can tell you with certainty is POST(Event:CloseWindow , , GLO:Thread) with
2 Commas and no Control is the correct syntax to send a Window event to another thread. POST() does not require a Control number, those are called Window Events.

You must have some other problems with your code. The value of GLO:Thread must be correct. That Thread must have an ACCEPT loop active and not blocked. The code must be in the correct place where Window Events are handled It must handle the event correctly, likely a BREAK. Etc. Sorry I cannot help with these currently.

@CarlBarnes I understand that POST(Event:CloseWindow (or Return Level:Fatal) will work if everything is correct with the code. I posted example here and I know that code is not correct (I don’t know how to write correct code :frowning: , otherwise I will not even started this thread).

@Daniel1

This is an example of what I think you are looking for to work out how you can achieve your goals

ThreadsExample.zip (325.2 KB)

It utilizes some of my alterations in my first response, but doesn’t use the stepped processing using the timer of that example.

Instead it uses a separate code template procedure for the processing. So the “MyProcedure” procedure “STARTS” a new thread, CodeThread.

Please study everything in the example, as there are a lot of changes, including an embed in the Global Embeds.

NOTIFY is used extensively, and it is worth studying this.

And finally, please, understand that you should never put code for processing anything in the .TakeEvent embed. Note how I have used a specific Event (EVENT:OpenWindow) to do what was needed.

Again, there is a lot to study, as I can’t really describe everything being done here.

I hope this helps.

Mark

1 Like

@Mark_Sarson Thank you a lot, again.
Will check everything in detail.
Thanks again!

@Mark_Sarson it looks like you sent my original file, can you please check?

Hi Danel, Try again, I’ve re created the zip and put up a link to thew new in my original post.

Let me know if there is still an issue.

Sorry about that.

Mark

@Mark_Sarson
Now it is OK, thank yo again, so I started testing different scenarios.
So I changed “CodeThread” procedure like this

 !Assign NotifyGroup to the passed address of the notify group
  NotifyGroup &= (ngAddress)
  DO OpenFiles
  loop L = 1 to (mLoop * 1000)
      clear(m:record)
      !set(m:idKey,m:idKey)
      !loop until access:myTable.next() <> level:benign
          !Code to process here
        m:name = 'Thread ' & THREAD() & ' - loop ' & L
        if access:myTable.insert() <> level:benign
          stop('Insert Error: '&errorcode()&' : '&error())
        end  
      !END
      !Fill notify group with values
      NotifyGroup.PercentComplete = L/(mLoop*10)*100
      NotifyGroup.OtherParam1 = 'Thread ' & THREAD() & ' - loop ' & L
      NOTIFY(NOTIFY:DisplayUpdate, threadID)
  END
  
  !Finished, so notify caller we have finished
  NOTIFY(NOTIFY:ProcessingComplete, threadID)
  DO CloseFiles

and I clicked on “Run MyProc” few times - this is what is happened:

image

@Mark_Sarson after I changed ID to guid, everything works perfect. Thank you so much.

1 Like