News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Dumb question about threads

Started by guga, July 07, 2018, 02:33:01 AM

Previous topic - Next topic

guga

Hi Guys

I know thread issues are being around for sometime but i´m struggling to understand completely. I´m trying to create a app that opens a imagee (with freeimage libraries) and display them on the proper screen (A client area). The problem relies that immediately after the image is loaded it needs to perform some checks for analyzing if the image is compressed or the levels of blur it may have etc. For that purpose, since it is heavy computation i putted the opening routine inside a thread using beginthreadex in msvcrt.

The problem is how i can be sure that the routines are finished before passing the rest of the functions ? I create it is something like this:

Main messages of the workspace where the image is loaded

Proc MainProc:
     Arguments @hWnd, @uMsg, @wParam, @lParam

.......
    ...Else_If D@uMsg = &WM_COMMAND

        call On_WmCommand D@hWnd, D@uMsg, D@wParam, D@lParam
        xor eax eax
.......
...Else_If D@uMsg = &WM_PAINT
......
etc etc etc


On_Wm_Command function is where the main thread is called like this:


Proc On_WmCommand:
    Arguments @hWnd, @uMsg, @wParam, @lParam
    Local @Count

    ...If D@wParam = M00_Open ; Open file from the menu

.............do some stuff, open image, put messagebox alerts in case of failure, etc
        C_call 'msvcrt._beginthreadex' &NULL, 0, OpenImageThread, &NULL, &THREAD_PRIORITY_NORMAL, OpenImgThreadId ; <----------------The main thread function
        mov ebx eax
        mov D$ButtonStatus 1
        ;call 'kernel32.WaitForSingleObject' ebx, &INFINITE <---------------------- Why ????????? I removed this because the function never ends, and enter on a infinite loop here never exiting the thread
        If ebx = &NULL
            call ReportWinError {'Debugger: CreateThread (Resource Manager)' 0}
        Else
            ; we don't need the thread handle
            call 'Kernel32.CloseHandle' ebx
        End_If

        xor eax eax
...End_If


The main thread function:

Proc OpenImageThread:
    Arguments @lpData
    ; Check for status of the menu, see if it is needed to use grayscale and so on
    ; access InvalidateRect, EnableWindow, Loadcursor and other windows apis on the main handle of the workspace and also on the handle of the main window.

     call DetectImageBlur ;<----- The main function responsible for checking if the image is blurred, and the compression it have. Also, this function places the proper messages with sprintf on the statusbar of the window, set new cursor etc.

    C_call 'msvcrt._endthreadex' 0 ; <---- End the thread
    mov D$ButtonStatus 0
    xor eax eax

EndP



So...is it the proper way to calling and ending the thread ? How can i make sure that once i opened a file and triggered the WM_COMMAND messages, the main routine OpenImageThread used in beginthreadex is fully and properly loaded before the program proceeds to the rest of the functions enabling menus only after the main routine is fully loaded etc etc ?


I tried to use CreateThread but i have the same questions and after reading somewhere that is better using beginthreadex for safety problems i decided to use it instead CreateThread.
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

zedd151

do a google search for 'CreateMutex' or 'Mutex Objects', I think that is what you are looking for.

Quote
You can use a mutex object to protect a shared resource from simultaneous access by multiple threads or processes

does that fit the bill?

There are others that also do similar to 'wait' until one process is finished before resuming another. You'll have to do a search as my memory is a little fuzzy. 

'CreateSemaphore'   ---

Quote
Using Semaphore Objects (Windows) - msdn.microsoft.com
https://msdn.microsoft.com/en-us/library/windows/desktop/ms686946...
The following example uses a semaphore object to limit the number of threads that can perform a particular task. First, it uses the CreateSemaphore function to create the semaphore and to specify initial and maximum counts, then it uses the CreateThread function to create the threads. Before a ...


hope this little bit of info helps

jj2007

You start the thread, and once it is ready, the thread sends a private (->RegisterWindowMessage) message to the main window:
  Case MyPrivateMessage
     Print "Great, now I can enable my menus!"

guga

Hi guys

Zed, i read it, but still confused :(

JJ, i tried the RegisterWindowMessage, but on M$ docs it says that it maybe better using  WM_USER. I tried both cases and nothing happened. I then tried to put a dummy flag inside the thread and just after it, enabled a TRUE fglag to check either the thread ended or not...but...nothing..:(

I´m doing something like this:
    mov D$DummyVar 1 ; Just a dummy var to see if the thread ended or not. In case, 1 means thread running
    C_call 'msvcrt._beginthreadex' &NULL, 0, OpenImageThread, &NULL, &THREAD_PRIORITY_NORMAL, OpenImgThreadId
    mov ebx eax
    If D$DummyVar = 0 ; If thread ended enable menus
        call Enablemenu ...............................
    End_If


Inside the thread it have:
Proc OpenImageThread:
    Arguments @lpData
....

    mov D$DummyVar 0 ; <---- Stteled the flag to 0 to say when the thread really ended...but..nothing is happenning :(
    C_call 'msvcrt._endthreadex' 0
    xor eax eax
EndP


The problem is that when the app starts, it goes to beginthreadex' and continues ....pass through DummyVar (jumping it, because the flag is still 1....and only later, it enter inside the thread function at OpenImageThread....but....it does not return and therefore, the next line of code that check for the DummyVar is not reached.

If i use the "call 'kernel32.WaitForSingleObject' ebx, &INFINITE" then the things got worst.

I´m really having troubles to understand how this whole thread thing works. Someone have examples of using this on a way that the app must check either the thread is fully ended or not ? (I mean, without the problem that it enter on a infinite loop) Examples using waitformultipleobjects, waitforsingleobjects, createthread, beginthreadex, createmutex etc etc ?
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

jj2007

Simple demo below. Just run the exe to see the logic.
GuiParas equ "Thread demo", x950, y20, w160, h120, cblack, b00FFFFD0h
include \masm32\MasmBasic\Res\MbGui.asm
  usedeb=1
  push eax
  invoke CreateThread, 0, 0, MyThreadProc, 111, 0, esp
  pop edx
  deb 4, "CT: handle, ID", eax, edx
Event Message
  inc msgCount
  deb 4, "msg", chg:msgCount ; , wParam, _lParam ; see deb
  .if uMsg==WM_USER+123
Print Str$("******** WM_USER arrived, wParam=%i", wParam_), Str$(", lParam=%i ********\n", lParam_)
MsgBox 0, "The thread ended, it seems", "Hi", MB_OK
mov eax, 123456789 ; retval for SendMessage
jmp @RetEax
  .endif
EndOfEvents

MyThreadProc:
  push ebx
  xor ebx, ebx
  .Repeat
invoke Sleep, 100
Print "*"
inc ebx
  .Until ebx>=30
  PrintLine " bye"
  pop ebx
  invoke SendMessage, hGui, WM_USER+123, 456, 789
  deb 4, "SendMessage WM_USER+123 retval", eax, $Err$()
  retn 4
GuiEnd


raymond

And you always should ask yourself what you will gain by running some code in a separate thread.

In your case, if you must complete that "heavy computation" before continuing with the main program, why put it in a separate thread? What will the remainder of your program do during that "heavy computation" in a separate thread?
How much computer time do you expect to save?
How much less code will you have to write?

Unless you are primarily experimenting with the use of threads for possible future use.... :dazzled:
Whenever you assume something, you risk being wrong half the time.
http://www.ray.masmcode.com

guga

Hi JJ. Many thanks...:)

I forgot to put the WM_USER indeed (Itr can be retrieved also with postmessage ?). But, what about the closethread ?

On your example you created the thread but when for correctly ending the thread with "ExitThread" or "endthreadex" inside the thread function "MyThreadProc" in your case or it can be placed somewhere else ? Also, on your example you used the value  111 as the thread parameter. This value is returned only after the thread is ended or it is reached without the thread ends (at pop edx, for example) ?

Hi Raymond, i have some difficulties in understanding the thread functionality in general usage.  But, on this case, specifically is for trying to make some functions/algorithms i´m using works a bit faster without "hanging' the whole app waiting to the function ends. I´m making some tests on algorithms related to image managment, such as a super resolution algorithm, blur detection and jpeg artifact detector that makes heavy usage in computation for large images (Well...not that large, but, it takes some few secs to finish the work).  I´m currently analyzing the functionality of these algorithms in order to try porting them to video (and not only images). Waiting 1 or 2 seconds is ok when it concerns only images, but for using on video it is aa different story because it needs to be faster then that, specially considering that a video can have 100.000 frames or something, so the faster the algorithms goes (without hanging the rest of the application that uses the algo) the better will be.

So, perhaps the best way is using threads to allow the rest of the application free to is being used while these functions/algorithms are being performed. Eventually, if i succeed to finish these algorithms i´ll give a test on a plugin for virtualdub and see how it works on video processing as well but, before that i need to understand these threads functionality completely
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

zedd151

Ah! This is about image processing and possible video processing?  Post a new topic perhaps, with image and/or video processing in the title. Maybe there are some members who have the solution for your problem. As Raymond suggested, it might not be necessary to having a separate thread running --  perhaps a better processing algorithm?

jj2007

Quote from: guga on July 13, 2018, 01:52:12 AMyou created the thread but when for correctly ending the thread with "ExitThread" or "endthreadex" inside the thread function "MyThreadProc" in your case or it can be placed somewhere else ? Also, on your example you used the value  111 as the thread parameter. This value is returned only after the thread is ended

From the old Win32.hlp:
QuoteExitThread is the preferred method of exiting a thread. When this function is called (either explicitly or by returning from a thread procedure), the current thread's stack is deallocated and the thread terminates

The 111 is given to the thread for its own use. Try this:
  invoke CreateThread, 0, 0, MyThreadProc, 22, 0, esp
...
  .Until ebx>=[esp+8]


You may return something in eax, and retrieve that value with GetExitCodeThread, but its rather useless in this case because your WM_USER+x message gives you already wParam and lParam.

guga

You may return something in eax, and retrieve that value with GetExitCodeThread, but its rather useless in this case because your WM_USER+x message gives you already wParam and lParam.


Ohn, i see. So, on this particular case i´ll use WM_USEr with sendmessage/postmessage instead. I´ll continue studying this thread functions for further usage. Eventually i´ll be forced to use some of these. I never used those before on a regular daily basis. Although these functions exists in RosAsm (For the debugger mainly), those routines were written by a collaborator at the time (Ludwig) and i didn´t have enough time to analyse all of those functions yet. I´ll probably have to understand it better, because i´ll restart working on RosAsm development as soon as possible.

QuotePost a new topic perhaps, with image and/or video processing in the title
Hi Zed. Yes, i´m seeing how this works now for image processing algorithm. I´m reading the new algorithm from google RAISR at https://www.pcmag.com/news/351027/google-raisr-intelligently-makes-low-res-images-high-quality and it is really promissing. I found some information on github but it is in python :(
https://github.com/movehand/raisr
https://github.com/volvet/RAISR-1
https://github.com/MKFMIKU/RAISR

Once i finish these routines i´m building i´ll post it here and open a new thread related to image/video processing. The routines  i´m trying to create are not related to this RAISR, but i´m trying to go slowly, learning what i can before (who knows :icon_mrgreen: :icon_mrgreen:) give a try eventually on this new google work.
The idea behind this RAISR  is amazing.  :eusa_clap: :eusa_clap: :eusa_clap:

Reading google paper "RAISR: Rapid and Accurate Image Super Resolution"  is a hard task for me to understand, but, one thing i though that can be implemented is the structure preservation using census transformation (example here: https://hangyinuml.wordpress.com/2012/09/08/census-transform-c-implementation). It takes onto account the position of the pixels related to each other rather then the chromacity or saturation, etc. Since it is blind to luma, it preserves the original structure of a given image, which can be useful for functions related to motion estimation, rotation, object extraction etc etc. Later i´ll open a specific thread for all of this :) It is really amazing.
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

jj2007

Quote from: guga on July 13, 2018, 05:28:02 AMi´ll use WM_USEr with sendmessage/postmessage

I would suggest SendMessage: In your WM_USER handler, the thread and its variables are still alive (e.g. an open file), so you can do some processing. With PostMessage, you can't be sure about the thread's state because it returns immediately.