News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Multithreaded Application Sharing Code.

Started by AgentSmithers, June 11, 2009, 03:46:21 AM

Previous topic - Next topic

AgentSmithers

In VB6 we have .Modules to share common code for other objections to execute the same code and to store it in its own memory space.

Now I got a Multithreaded Application and they need to access the same code.

Whats a better soulation then to just mearly copy and paste the same code over and over?

hutch--

Unless I have misunderstood your question, you just do the same thing as you did in VB. As long as the code and data is available within the scope of the thread code each thread will use the same code while remaining independent of other threads using the same code.

It can get messy if you use the same variables between threads as you can get conflicts if the variables are changed but to answer your question, write a module that you can use in more than one thread and call it as many times as you like.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

MichaelW

This creates the threads with the CRT to keep the code simple and compact. Build as a console app.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
      counter dd 200
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

threadproc proc junk:DWORD

    @@:
      invoke GetCurrentThreadId
      print uhex$(eax)
      invoke Sleep,10
      dec counter
      jns @B

      ;------------------------------------------
      ; The thread terminates automatically when
      ; the thread procedure returns.
      ;------------------------------------------

      ret

threadproc endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    invoke crt__beginthread, threadproc, 0, 0
    invoke crt__beginthread, threadproc, 0, 0

    ;--------------------------------------------------
    ; Delay long enough for both threads to terminate.
    ;--------------------------------------------------

    invoke Sleep, 3000

    print chr$(13,10,13,10)
    inkey "Press any key to exit..."
    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start


eschew obfuscation

Slugsnack

bear in mind if you want to avoid variable conflict simply have the variables that you are gonna change in local variables instead of global ones

AgentSmithers


AgentSmithers

Now Im doing something as simple as .486
.model flat, stdcall
option casemap :none

;include \masm32\include\windows.inc

;include \masm32\include\user32.inc
;include \masm32\include\kernel32.inc
;include \masm32\include\masm32.inc
include \masm32\include\masm32rt.inc

;includelib \masm32\lib\user32.lib
;includelib \masm32\lib\kernel32.lib
;includelib \masm32\lib\masm32.lib
includelib \masm32\lib\masm32rt.lib

.data
    Var db 16 dup ("0"); Set 16 Bytes of value "0"
    Var1 db "Hello1"
    Var2 db "Hello2"
    InputBuffer db 16 dup (0)
    MyNumber dd 0

.data?
    STDHandle dd ?
    buffer db ?
    Number dd ?
    BytesToOutput db ?
    ThreadID DWORD ?

.code
    start:
        invoke GetStdHandle, -11
        mov STDHandle, eax     
       
        mov  eax,OFFSET ThreadProcOne
        invoke CreateThread,NULL,NULL,eax,NULL,0,ADDR ThreadID
        invoke CloseHandle,eax
       
        ;mov  eax,OFFSET ThreadProcTwo
        ;invoke CreateThread,0,NULL,eax,NULL,0,ADDR ThreadID
        ;invoke CloseHandle,eax
       
        invoke StdIn,ADDR buffer, LENGTHOF buffer
        ret ; You have to Return to Exit Properly or the program will crash!

ThreadProcOne PROC Param:DWORD
    lea esi, offset Var1
    xor ecx, ecx
    mov cx, 10
    myloop:
    ;inc MyNumber
    invoke WriteConsoleA, STDHandle, str$(ecx), 6, EDX, 0 ;Uses 2Byte Tchar's
    invoke Sleep, 1000
    loop myloop
    ret
ThreadProcOne ENDP

ThreadProcTwo PROC ;USES ecx Param:DWORD
    lea esi, offset Var2
    invoke WriteConsoleA, STDHandle, esi, 6, EDX, 0 ;Uses 2Byte Tchar's
    ret
ThreadProcTwo ENDP
                       
                    end start

                    BackupToStart:

                        ;invoke StdIn,ADDR buffer, LENGTHOF buffer
                   
                        ret ; You have to Return to Exit Properly or the program will crash!

                    end BackupToStart


And it keeps outputting a Large number, Why isent it counting down from 10?

dedndave

not sure, but you might try using ecx (not cx)
and pushing it across the invoke

mov ecx,10
push ecx
invoke
pop ecx
loop

Slugsnack

okay first off you don't have to mov eax, offset threadproc.  in the lpProc just put addr threadproc.  secondly there is no handle to close, not sure why you're doing that.  thirdly if you're not using threadid don't get it.

in threadprocone, you zero ecx then mov 10 to cx ?  faster to mov 10 to ecx in the first place.  the reason it keeps going is because in stdcall, which is what winapi uses eax/ecx/edx aren't necessarily preserved so ecx is modified in both calls..

again.. threadproc2.  you can just do addr var2.  not sure why you have that backtostart stuff.

btw if you want to exit by waiting for both threads to complete, then use the threadids.  or pass in events that the thread sets when it's done.  or a global variable, there are multiple ways.  also you should probably use exitprocess instead of ret to exit the main function.  if you wanna wait for user input btw you can always use inkey or __kbhit() which is what inkey uses

dedndave

Quote from: dedndave on June 11, 2009, 10:42:00 PM
not sure, but you might try using ecx (not cx)
and pushing it across the invoke

mov ecx,10
push ecx
invoke
pop ecx
loop


AgentSmithers

Slugsnack, I feel like you just slammed me mentally, But I do not mind be belittled if you have the right answer =D  :cheekygreen:

Edit:

mov  eax,OFFSET ThreadProcOne
invoke CreateThread,NULL,NULL,eax,NULL,0,ADDR ThreadID

Works but ADDR threadProcOne in the invoke gives Undefined, Fixed it by making a Proto.

Which STDCalls are effecting ECX in my case. The Invoke to WriteConsoleA, should I use a different calling convention that wont effect ECX, if so which one and how?

Now I got

.486
.model flat, stdcall
option casemap :none

;include \masm32\include\windows.inc

;include \masm32\include\user32.inc
;include \masm32\include\kernel32.inc
;include \masm32\include\masm32.inc
include \masm32\include\masm32rt.inc

;includelib \masm32\lib\user32.lib
;includelib \masm32\lib\kernel32.lib
;includelib \masm32\lib\masm32.lib
includelib \masm32\lib\masm32rt.lib

ThreadProcOne proto

.data
    Var db 16 dup ("0"); Set 16 Bytes of value "0"
    Var1 db "Hello1"
    Var2 db "Hello2"
    InputBuffer db 16 dup (0)
    MyNumber dd 0

.data?
    STDHandle dd ?
    buffer db ?
    Number dd ?
    BytesToOutput db ?
    ThreadID DWORD ?

.code
    start:
        invoke GetStdHandle, -11
        mov STDHandle, eax     
       
        invoke CreateThread,NULL,NULL,OFFSET ThreadProcOne,NULL,0,ADDR ThreadID
       
        ;mov  eax,OFFSET ThreadProcTwo
        ;invoke CreateThread,0,NULL,eax,NULL,0,ADDR ThreadID
        ;invoke CloseHandle,eax

        invoke Sleep, 10000
       
        invoke StdIn,ADDR buffer, LENGTHOF buffer
        ret ; You have to Return to Exit Properly or the program will crash!

ThreadProcOne PROC
    lea esi, offset Var1
    mov ecx, 10
    myloop:
    ;inc MyNumber
    push ecx
    invoke WriteConsoleA, STDHandle, str$(ecx), 6, EDX, 0 ;Uses 2Byte Tchar's
    pop ecx
    invoke Sleep, 1000
    dec cx
    jnz myloop
    ret
ThreadProcOne ENDP

ThreadProcTwo PROC ;USES ecx Param:DWORD
    lea esi, offset Var2
    invoke WriteConsoleA, STDHandle, esi, 6, EDX, 0 ;Uses 2Byte Tchar's
    ret
ThreadProcTwo ENDP
                       
    end start

                    BackupToStart:

                        ;invoke StdIn,ADDR buffer, LENGTHOF buffer
                   
                        ret ; You have to Return to Exit Properly or the program will crash!

                    end BackupToStart


It says 10, then a real high number over and over(same number)

dedndave

i posted it - lol
read it

mov ecx,10

push ecx
invoke
pop ecx

loop


Slugsnack

this is something like how i would have coded it

include \masm32\include\masm32rt.inc

ThreadProcOne proto
ThreadProcTwo proto

.data

bThreadOneActive    bool    TRUE
bThreadTwoActive    bool    TRUE

.data?

.code
    Start:

xor ebx, ebx
    invoke AllocConsole

    invoke CreateThread, ebx, ebx, addr ThreadProcOne, ebx, ebx, ebx
    invoke CreateThread, ebx, ebx, addr ThreadProcTwo, ebx, ebx, ebx

    .WHILE bThreadOneActive || bThreadTwoActive

            invoke Sleep, 100

    .ENDW

        print "Both threads exited !", 13, 10

    @@:

    invoke Sleep, 100
    invoke crt__kbhit
test eax, eax
jz @b

    invoke FreeConsole
    invoke ExitProcess, ebx

ThreadProcOne proc

mov esi, 10

    @@:
   
    invoke Sleep, 100
        print "Hello1", 13, 10

dec esi
test esi, esi
jnz @b

;mov ecx, 10
;
;   @@:
;
;push ecx
;   invoke Sleep, 100
;       print "Hello1",13, 10
;
;pop ecx
;dec ecx
;test ecx, ecx
;jnz @b

mov bThreadOneActive, FALSE

ret
ThreadProcOne endp

ThreadProcTwo proc

        print "Hello2", 13, 10

mov bThreadTwoActive, FALSE

ret
ThreadProcTwo endp

    end Start


as dave quite rightly said if you use ecx as the counter you can use loop.  i personally don't use that instruction since apparently on newer processors they don't make instructions like that fast anymore.

i put sleep into the loop to show that the main thread will wait until both the others are done until it continues.  instead of the global variable you could use an event which is passed in as the thread parameter.

if you don't sleep the printing loop you may find some problems when both threads try to write to the console at the same time.  especially since when you do print and 13, 10 it outputs the string and the 13, 10 in two different calls.  i guess you can make a wrapper to print that is in a critical section to solve this but it seems a bit overkill haha.  there tend to be better ways to do things than have 2 threads write unsynchronised things to the console

sorry for 'slamming you mentally' it was unintended  :'(

AgentSmithers

Ahh Duh I found it, Yes after I pop ECX I use another STDCall with Sleep and that overwrites the register.

.486
.model flat, stdcall
option casemap :none

;include \masm32\include\windows.inc

;include \masm32\include\user32.inc
;include \masm32\include\kernel32.inc
;include \masm32\include\masm32.inc
include \masm32\include\masm32rt.inc

;includelib \masm32\lib\user32.lib
;includelib \masm32\lib\kernel32.lib
;includelib \masm32\lib\masm32.lib
includelib \masm32\lib\masm32rt.lib

ThreadProcOne proto

.data
    Var db 16 dup ("0"); Set 16 Bytes of value "0"
    Var1 db "Hello1"
    Var2 db "Hello2"
    InputBuffer db 16 dup (0)
    MyNumber dd 0

.data?
    STDHandle dd ?
    buffer db ?
    Number dd ?
    BytesToOutput db ?
    ThreadID DWORD ?

.code
    start:
        invoke GetStdHandle, -11
        mov STDHandle, eax     
       
        invoke CreateThread,NULL,NULL,OFFSET ThreadProcOne,NULL,0,ADDR ThreadID
       
        ;mov  eax,OFFSET ThreadProcTwo
        ;invoke CreateThread,0,NULL,eax,NULL,0,ADDR ThreadID
        ;invoke CloseHandle,eax

        invoke Sleep, 10000
       
        invoke StdIn,ADDR buffer, LENGTHOF buffer
        ret ; You have to Return to Exit Properly or the program will crash!

ThreadProcOne PROC
    lea esi, offset Var1
    mov ecx, 10
    myloop:
    ;inc MyNumber
    push ecx
    invoke WriteConsoleA, STDHandle, str$(ecx), 6, EDX, 0 ;Uses 2Byte Tchar's
    invoke Sleep, 1000
    pop ecx
    loop myloop
    ret
ThreadProcOne ENDP

ThreadProcTwo PROC ;USES ecx Param:DWORD
    lea esi, offset Var2
    invoke WriteConsoleA, STDHandle, esi, 6, EDX, 0 ;Uses 2Byte Tchar's
    ret
ThreadProcTwo ENDP
                       
    end start

                    BackupToStart:

                        ;invoke StdIn,ADDR buffer, LENGTHOF buffer
                   
                        ret ; You have to Return to Exit Properly or the program will crash!

                    end BackupToStart


Umm did some reading on the STD call, EAX useuly returns the Value pointing from Invoke but. What does ECX and EDX return from something as simple as sleep?

dedndave

hard to say
i have not found a document that says anything is preserved across an API call
i would like to know, as well, if there is such a doc
not just registers, but flags - especially the direction flag
it would be nice to know what the spec is

AgentSmithers

QuoteThe __stdcall convention is mainly used by the Windows API, and it's a bit more compact than __cdecl. The main difference is that any given function has a hard-coded set of parameters, and this cannot vary from call to call like it can in C (no "variadic functions").

Because the size of the parameter block is fixed, the burden of cleaning these parameters off the stack can be shifted to the called function, instead of being done by the calling function as in __cdecl. There are several effects of this:

   1. the code is a tiny bit smaller, because the parameter-cleanup code is found once — in the called function itself — rather than in every place the function is called. These may be only a few bytes per call, but for commonly-used functions it can add up. This presumably means that the code may be a tiny bit faster as well.
   2. calling the function with the wrong number of parameters is catastrophic - the stack will be badly misaligned, and general havoc will surely ensue.
   3.

      As an offshoot of #2, Microsoft Visual C takes special care of functions that are B{__stdcall}. Since the number of parameters is known at compile time, the compiler encodes the parameter byte count in the symbol name itself, and this means that calling the function wrong leads to a link error.

      For instance, the function int foo(int a, int b) would generate — at the assembler level — the symbol "_foo@8", where "8" is the number of bytes expected. This means that not only will a call with 1 or 3 parameters not resolve (due to the size mismatch), but neither will a call expecting the __cdecl parameters (which looks for _foo). It's a clever mechanism that avoids a lot of problems.

Yeah, It appears that EBP plays a big roll on restoring the Stack once the Function has returned with STD call but in__Cdecl it appears that the Function itself is responcable to clearing the stack before it returns, Any enlightenment on this?

EDIT:
I found this.
Quote__stdcall is not an instruction, it is a type modifier which tells the compiler to use the "standard" calling convention for invokations of the function it applies to.

When a function is called, the parameters are pushed onto the stack. These parameters must be cleaned up after the function call returns. This could be done by the calling code (caller) or the function which is called (callee).

For __stdcall, the callee cleans the stack. For __cdecl, the caller cleans it. There are other calling conventions as well.

I might have it backwards =(

-Agent