[Win32API] Multithreading problem

so I want to create 2 threads that will do something, but both of them will start with different starting number, however they will BOTH will get the same number UNLESS I add Sleep(10) (5 works too) between thread initialization, is there any other way to fix this (other than sleep or timer)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void loop(void *param)
{
	int mystart = iStartWith;
	while(1)
	{
		char tmp[32];
		wsprintf(tmp, "%i", mystart);
		MessageBox(NULL, tmp, tmp, NULL);
		Sleep(1000);
	}
	_endthread;
}

void myfunc()
{
iStartWith = 0;
loop_thread[0] = (HANDLE)_beginthread(loop, 0, NULL);
iStartWith = 100;
loop_thread[1] = (HANDLE)_beginthread(loop, 0, NULL);
}
If you find yourself prefixing a thread subject with [Win32API] you should, perhaps, post it in the Windows Programming forum (note that you can still move this thread to the appropriate forum.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <string>
#include <process.h>
#include <Windows.h>

void _cdecl show(void *param)
{
    std::string message = std::to_string(reinterpret_cast<int>(param)) ;
    MessageBoxA(NULL, message.c_str(), message.c_str(), 0) ;
    _endthread() ;
}


void doThreads()
{
    for ( unsigned i=0; i<10; ++i )
        _beginthread(show, 0, reinterpret_cast<void*>(i)) ;
}

int main()
{
    doThreads() ;
    MessageBoxA(NULL, "We're done here!", "Finished", 0) ;
}
usually when I post in the Windows Programming forum I have to wait 2-3 days for response, osmetimes I don't even get one after 2-3 bumps

anyway thanks for the code, I understand everything but this part

reinterpret_cast<int>(param)

I know where param comes from, but what is reinterpret_cast<int> ?

edit1: and why do you have _cdecl in the function name?

edit2: is HANDLE loop_thread unnecessary? since u're not using it at all

edit3: how can I pass more arguments? for example 2 ints and 1 string/char
Last edited on
i have some simple knowledge about reinterprete_cast.
it really cast one variable/object to a fundamentally different type, if i was correct, it just takes the exact bit string that forms the object and casts it to the target type.
i think this cast occurs in runtime.

you have 3 more questions, but my experience is really tiny in this domain, i don't know their answers.
so is it something like stringstream? so for example when you have

int a = 50;
and oyu want to transfer it to char type, the value of char variable wont be "2" (50 is decimal value of "2") but 50? (so char array contains "50" string)
sort of:
usually casting int to char is performed with static_cast, it really does the cast in compile time, you don't need interpret cast in here.
you got the casting correctly between int and char, but the reinterpret_cast works with fundamentally different types, consider this useless example:
1
2
long long *x;
x = reinterpret_cast <long long *> (std::cin);

i guess this will compile fine, even though cin is an object of the istream class.
this is how this cast works, it takes the exact bits that forms the source object and casts it to be of the destination type, it reinterprets those bits.
See Reinterpret Cast section on this page

Type Casting
http://www.cplusplus.com/doc/tutorial/typecasting/

Also note that:

- the _beginthread function is deprecated is known to be unsafe in some circumstances; you should use the newer _beginthreadex instead.

It's safer to use _beginthreadex than _beginthread. If the thread that's generated by _beginthread exits quickly, the handle that's returned to the caller of _beginthread might be invalid or point to another thread.

_beginthread, _beginthreadex
http://msdn.microsoft.com/en-us/library/kdzttdcb%28v=vs.110%29.aspx
(See comments in MSDN entry for further details.)

- an explicit call to _endthread() /_endthreadex() is not needed if you're just about to exit the thread proc anyway.

- And __cdecl should have two leading underscore, if you want to be up date (things relating to the compiler (usually) have two leading underscores, those relating to the CRT a single underscore.)

Andy

Edit correction re deprecation of _beginthread (thanks to cire)
Last edited on
edit1: and why do you have _cdecl in the function name?


__cdecl specifies the calling convention. It is required here as the thread proc is being called back by the system and you have to be sure that you agree on the calling convention for this to be safe.

(With __cdecl calls, the caller is responsible for cleaning up the stack when the call returns; with __stdcall, it's the callee who does the cleanup)

edit2: is HANDLE loop_thread unnecessary? since u're not using it at all

With _beginthread the handle can be ignored as the threads clean up after themselves automatically (the handle is closed)

With _beginthreadex you do have to close the handle yourself.

edit3: how can I pass more arguments? for examp

Like this (this version also uses _beginthreadex, rather than _beginthread.

You can also see I am using a wait function, which is also possible with the new function (as MSDN say: "You are also able to use the thread handle returned by _beginthreadex with the synchronization APIs, which you cannot do with _beginthread.")

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <string>
#include <process.h>
#include <Windows.h>

struct Data // lazy struct
{
    Data(int id_, const std::string& title_)
    : id(id_), title(title_) { }

    int         id;
    std::string title;
};

unsigned __stdcall show_thread_proc(void *param)
{
    Data* data = reinterpret_cast<Data*>(param);
    std::string message = std::to_string(data->id);
    MessageBoxA(NULL, message.c_str(), data->title.c_str(), MB_OK | MB_ICONEXCLAMATION);
    delete data;
    return 0;
}

void doThreads()
{
    const unsigned num_threads = 10;
    HANDLE hthreads[num_threads] = {0};
    for ( unsigned i=0; i<num_threads; ++i ) {
        Data* data = new Data(i, "Hello world!");
        hthreads[i] = (HANDLE)_beginthreadex(0, 0, show_thread_proc,
                                    reinterpret_cast<void*>(data), 0, 0) ;
        // do not delete data -- that's up to thread
    }
    // Here, TRUE means wait for all threads, rather than just any
    // single thread, to signal
    WaitForMultipleObjects(num_threads, hthreads, TRUE, INFINITE);
    for ( unsigned i=0; i<num_threads; ++i ) {
        CloseHandle(hthreads[num_threads]);
    }
}

int main()
{
    doThreads() ;
    MessageBoxA(NULL, "We're done here!", "Finished", 0) ;
}


Andy
Last edited on
- the _beginthread is deprecated; you should use _beginthreadex instead. See comments in MSDN entry for details.


I understand why _beginthreadex should be preferred over _beginthread, but I don't see anything anywhere about _beginthread being deprecated.

thank you andy, but since my english is limited I have to ask you if u could say it in some easy words IF I get this wrong:

1. (I have no idea what is calling convention) so this will make sure that the _beginthread() calls the right function? also why do you call delete in stdcall? isn't data supposed to be in only that function since it's created in there?

2. I got this one

3. what will this do?

1
2
Data(int id_, const std::string& title_)
    : id(id_), title(title_) { }


WaitForMultipleObjects will wait for all thread functions to finish (return 0;)?
@cire Thanks for the correction re deprecation of _beginthread; I've corrected my post accordingly.

I checked my other facts, but blatantly assumed the presense of the -ex version implied deprecation of the older function.... :-\

Andy
Last edited on
@mekkatorqu

1 (a) Calling convention:

so this will make sure that the _beginthread() calls the right function

In a nut shell, a calling convention is "a scheme for how subroutines receive parameters from their caller and how they return a result."

(stolen from wikipedia.org : Calling convention
www://en.wikipedia.org/wiki/Calling_convention )

So it's more that it makes sure the function is called in the right way (or that the function is right for the way it's called?)

Most cpus (inc. all well known ones, I believe) use the stack to pass parameter data when making function calls. The convention is therefore (a) what order the data is pushed onto (and popped off) the stack, (b) who is responsible for cleaning the stack up when the function returns, and (c) how the return code is passed back to the calling function (both stdcall and cdecl use registers -- differently -- to handle the return code.)

For 32-bit Windows, the most common calling conventions are cdecl and stdcall, for C (or C-style C++) functions and static class member functions, and thiscall, which is used when calling non-static class member functions. There is also fastcall, where function arguments are passed in registers when possible, but this is less common than the other three.

Calling Conventions
http://msdn.microsoft.com/en-us/library/k2b2ssfy.aspx

Argument Passing and Naming Conventions
http://msdn.microsoft.com/en-us/library/984x0h58.aspx

The important thing is that the caller and callee must follow the same convention. This won't usually effect calls within a module, unless you deliberately make life difficult for yourself. But when calling a DLL or using system callbacks (like the thread proceedure which is passed to _beginthreadex and the WindowProc registered for a window class.) architecture, you need to be careful.

Andy

Call stack
http://en.wikipedia.org/wiki/Call_stack

Calling convention
http://en.wikipedia.org/wiki/Calling_convention

x86 calling conventions
http://en.wikipedia.org/wiki/X86_calling_conventions
Last edited on
@mekkatorqu

1 (b) delete

why do you call delete in stdcall?

This is unconnected with the change from __cdecl to __stdcall; that happed as _beginthread uses __cdecl and _beginthreadex uses __stdcall.

The delete is needed as I modified the code to should how to pass more than one argument. Well, you still only have one argument, but you can make it a pointer than points at whatever size data you want.

I used new and delete to decouple the lifetime of the data from that the calling function. If you know that the thread will end before the function which started it returns, you can just pass the address of a stack variable. But putting the data on the stack is safer.

Andy
Last edited on
@mekkatorqu

3. constructor initializer list

what will this do?
1
2
Data(int id_, const std::string& title_)
    : id(id_), title(title_) { }


This version of the constructor is using an initializer list to set the values of the member variables during construction.

It does the same thing as:

1
2
3
4
Data(int id_, const std::string& title_) {
    id = id_;
    title = title_;
}


but all the work is done before the body of the constructor is entered.

When the member variable is a built-in type, like an int or double, there in unlikely to be any difference in the machine code generated by the compiler in these two cases.

But when the member is a class, the initilizing constructor will be fired in the first case, but the default constructor and then operator= in the latter case, so there could be a performance hit.

To avoid any possible performance issues, and to be consistent, you should always use the constructor initializer list for member variables (when possible.)

Andy

PS Also see "Initializer list" section on this page:

Initialization (programming)
http://en.wikipedia.org/wiki/Initializer_list

This article:

Member Initialization List over Assignment
http://www.cplusplus.com/articles/1vbCpfjN/

And maybe these older threads?

Member Initialization List over Assignment
http://www.cplusplus.com/forum/articles/17820/

Constructor initialization list
http://www.cplusplus.com/forum/general/86163/
Last edited on
thanks! useful as always :)
Topic archived. No new replies allowed.