Help in multithreading

I just don't quite get why the tutorials i find about this has to go into all the crap that can go wrong while multithreading before I actually get to multithread. Anyways can you guys help I'm trying to make a simple program where one thread keeps typing 1 ever 1 second and another thread stops the other thread when I press enter and then starts again when I press enter. I've come so far.

[code]#include
bool run=true;
void workerThread()
{
while(run)
{
cout<<1<<endl;
Sleep(1000);
}
}
void main()
{
while(true)
{
getchar();
if(run==false)run=true;
else if(run==true)run=false;
}
}[/code]
Right now workerThread isn't even running, don't quite know how to start a thread.
«1

Comments

  • Threads are system specific. What OS are you using?
  • : Threads are system specific. What OS are you using?
    oh okay I'm using Windows XP, Borland C++ Builder 6
  • Then you should use [link=http://msdn2.microsoft.com/en-us/library/ms682453.aspx]CreateThread()[/link].

    First some very basic stuff:

    Coding style: use empty lines between parts of the program that aren't related, to make it readable. Put the inside of the if-statement on a new line.

    Programming practice: avoid global variables, since they cause "spaghetti code". There are very few cases where you need to use them. They will be especially troublesome when used in a multithreaded program and you forgot to declare them as "volatile". That will automatically lead to very serious and hard-to-detect bugs caused by the optimizer. So just avoid global variables and you'll be fine.

    Next, ANSI C++. void main() is not allowed in the standard, and has never been. It will only work on compilers that does not follow standard C++, ie poor compilers. Use int main().

    Same goes for , it was made obsolete 12 years ago. The common way to replace it is by typing:

    #include
    using namespace std;


    Now to the advanced stuff. CreateThread expects a callback function of the format

    DWORD WINAPI nameHere (LPVOID lpParam);

    If you use another format, you will get wrong calling convention, and end up with crashes.

    Since the thread is running in a separate memory space, it is good design to wait for all threads to finish before you close the program. The best way to do this is to use the Win32 wait functions WaitForSingleObject() or WaitForMultipleObjects(). These are good, effective functions which will let other programs/threads access the CPU while your program is waiting.

    The proper way to end a thread is to let it run to the end. By passing the "run" variable you had in your program to the thread as a parameter, we can tell the thread to end whenever we wish.


    [code]
    #include
    #include

    DWORD WINAPI workerThread(LPVOID lpParam);

    int main()
    {
    bool run = true;

    HANDLE hThread;
    DWORD dwThread_id;

    hThread = CreateThread(NULL, // default security attributes
    0, // use default stack size
    workerThread, // thread function
    &run, // argument to thread function
    0, // use default creation flags
    &dwThread_id); // returns the thread identifier



    /* the main() program goes here: */

    std::cin.get();

    /* end of main() program */



    run = false;

    WaitForSingleObject(hThread, INFINITE); // wait for the thread to finish cleanly

    std::cout << "main() finished" << std::endl;

    return 0;
    }


    DWORD WINAPI workerThread(LPVOID lpParam)
    {
    bool run;

    do
    {
    std::cout << "1" << std::endl;
    Sleep(1000);
    run = * (bool*)lpParam;
    } while(run);

    std::cout << "Thread finished" << std::endl;

    return 0;
    }
    [/code]
  • Thank you very much! This has been very helpful. I'll just have to look up what the new types mean. SUNSHINE at you forever!
  • [code]run = * (bool*)lpParam;[/code]
    I get confused of that how would you explain it in words?
  • : Then you should use
    : [link=http://msdn2.microsoft.com/en-us/library/ms682453.aspx]CreateTh
    : read()[/link].
    :

    Not that I know anything about threading, but there is an article which explicitly advises against using the API call when using the C library:
    http://www.flounder.com/badprogram.htm#CreateThread

    Wouldn't it be advisable to use _beginthread() instead of the API to make sure the code runs smoothly?
    Best Regards,
    Richard

    The way I see it... Well, it's all pretty blurry
  • : : Then you should use
    : : [link=http://msdn2.microsoft.com/en-us/library/ms682453.aspx]CreateTh
    : : read()[/link].
    : :
    :
    : Not that I know anything about threading, but there is an article
    : which explicitly advises against using the API call when using the C
    : library:
    : http://www.flounder.com/badprogram.htm#CreateThread
    :
    : Wouldn't it be advisable to use _beginthread() instead of the API to
    : make sure the code runs smoothly?
    : Best Regards,
    : Richard
    :
    : The way I see it... Well, it's all pretty blurry

    Hmm exactly why I posted this question here, its too much on that link you sent. Anyways stick to my question.
  • run = * (bool*)lpParam;

    To understand this, you first need to know a bit about the weird thing called "Hungarian notation" that MS used to name everything when they created the Win API. The prefix "LP" before the rest of the variable type means it is a pointer. Without Hungarian notation, the function prototype would look like this:

    int WINAPI workerThread(void* lpParam);

    Every pointer type may be typecasted to and from void pointers. Knowing this, I pass a pointer to a bool-variable in main() when I create the thread. We want to use pointers so that when the contents of the variable changes in main(), the thread function will automatically use the updated value.

    Since the thread can be certain that it will always receive a bool*, I can safely typecast to a (bool*). The * before the typecast is there to get the contents of what the pointer points at.

    ---

    Regarding the usage of CreateThread(), as you might have noticed we just had that debate here last week:

    http://www.programmersheaven.com/mb/Win32API/366223/366223/ReadMessage.aspx?S=B20000

    The conclusion I made is that [italic]if you are writing a C program on MS compilers and are generally clueless about thread-safety[/italic], use beginthread instead, because MS compilers have a bug in their library-picking. Though someone experienced in multi-threading already knew that C library functions aren't usually thread-safe, no matter compiler.

    If you use the beginthread() functions, you will get a compiler error on VC++ if you haven't explicitly told the compiler that you wish to use multi-threaded libraries, which seems to be the sole reason why MS tells us not to use it. They are in other words assuming that you use Visual Studio in the Win API docs... Other compilers won't have this problem.

    So for this to apply you need to:

    Call the same C library function from more than one thread
    AND
    Use a MS compiler
    AND
    You must be clueless about thread-safety.


    The OP is writing in C++ and using C++ library functions, so that issue does not apply here. He should use CreateThread because beginthread is an old and probably soon-to-be-obsolete function, with other problems in itself. If you are writing in C and using the C libraries from more than one thread, then use _beginthreadex() which is supposed to be safer than beginthread().

    The whole confusion about the topic is the older Win API documentation saying:

    "A thread that uses functions from the C run-time libraries should use the beginthread and endthread C run-time functions for thread management rather than CreateThread and ExitThread. Failure to do so results in small memory leaks when ExitThread is called."

    It sounds dangerous and odd. Memory leaks!? In the newer versions of the Win API docs, this text has been replaced by:

    "A thread in an executable that calls the C run-time library (CRT) should use the _beginthreadex and _endthreadex functions for thread management rather than CreateThread and ExitThread; this requires the use of the multi-threaded version of the CRT. If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions."

    Now it makes more sense suddenly. Also you can find a rather amusing remark at the bottom of the MSDN page for CreateThread():

    "So if you don't plan on running out of memory (and who does!) then you can use either _beginthread() or CreateThread(). Do you feel lucky?"
  • :
    : Regarding the usage of CreateThread(), as you might have noticed we
    : just had that debate here last week:
    :
    : http://www.programmersheaven.com/mb/Win32API/366223/366223/ReadMessag
    : e.aspx?S=B20000
    :
    : ...
    :
    : "So if you don't plan on running out of memory (and who does!) then
    : you can use either _beginthread() or CreateThread(). Do you feel
    : lucky?"
    :

    I knew I got the link to the article from somewhere around here ;)

    Thanks for the explanation. I didn't think beginthread was only there to give a nice warning.

    Best Regards,
    Richard

    The way I see it... Well, it's all pretty blurry
  • : "So if you don't plan on running out of memory (and who does!) then
    : you can use either _beginthread() or CreateThread(). Do you feel
    : lucky?"
    Thanks I'll use this, I'm a beginner at programming so I guess I feel lucky :P.
  • The point with using CreateThread() is that all modern program uses it, and the mentioned good functions like WaitForSingleObject() will only work with threads created with this function.

    As you can see from that link about bad programming habits, the Win API consists of good functions, neutral functions and evil functions :-). Use as many of the good ones as possible, and avoid the evil ones entirely. WaitForSingleObject() is a good one, while beginthread is among the evil ones, it has several issues, see the docs. But in the case mentioned, it is a necessary evil.
  • Okay I've been busy with school lately but now its, mm uh "break week" or something. So I was thinking of making a simple spaceinvader game but that can wait till I understand this first. In the code
    [code]run=*(bool*)lpParam;[/code]
    Now I know I'm not supposed to use global variables so how would you write the code to do the same thing with "run" as with int x and y? and what if I wanted to use a struct that includes run,x,y
    [code]struct controlstuff
    {
    bool run;
    int x;
    int y;
    };[/code]
    [code]#include
    #pragma hdrstop
    #include
    #include
    int x=1,y=1;
    DWORD WINAPI workerThread(LPVOID lpParam)
    {
    bool run=true;
    int letter=8;
    while(run)
    {
    gotoxy(x,y);
    cout<<(char)letter;
    run=*(bool*)lpParam;
    letter++;
    if(letter>255)
    letter=8;
    Sleep(1);
    }
    return 0;
    }
    int main()
    {
    _setcursortype(_NOCURSOR);
    bool run=true;
    HANDLE hThread;
    DWORD dwThread_id;
    hThread = CreateThread(NULL,0,workerThread,&run,0,&dwThread_id);

    char command;
    while(command!='q')
    {
    command=getch();
    if(command=='a')
    x--;
    else if(command=='d')
    x++;
    else if(command=='w')
    y--;
    else if(command=='s')
    y++;
    else if(command=='c')
    clrscr();

    if(y<0)
    y=1;
    if(x<0)
    x=1;
    }

    run=false;
    WaitForSingleObject(hThread, INFINITE);
    return 0;
    }[/code]
  • That program has several problems, two that are fatal.

    First, I didn't say you should stay away from global variables solely because they are poor programming style. I quote my previous post:

    "They will be especially troublesome when used in a multithreaded program and you forgot to declare them as "volatile". That will automatically lead to very serious and hard-to-detect bugs caused by the optimizer. So just avoid global variables and you'll be fine."

    Second, the conio library is an old remain from DOS. I am almost certain it is unsafe for multithreaded programs. If you use it, you will sooner or later get very hard-to-detect bugs. What you will have to do in order to avoid this, is to write ugly wrappers, like this:

    [code]void safe_gotoxy(int x, int y)
    {
    EnterCriticalSection(&cs);
    gotoxy(x, y);
    LeaveCriticalSection(&cs);
    }

    char safe_getch()
    {
    char ch;

    EnterCriticalSection(&cs);
    ch = getch();
    LeaveCriticalSection(&cs);

    return ch;
    }

    void safe_clrscr()
    {
    EnterCriticalSection(&cs);
    clrscr();
    LeaveCriticalSection(&cs);
    }


    int main()
    {
    static CRITICAL_SECTION cs;

    InitializeCriticalSection(&cs);
    ... call functions here
    DeleteCriticalSection(&cs);
    }
    [/code]
  • Okay but how to write the multithreading so that it can get x and y?

    Oh and also you know of anyother way to write to the dos-screen without using "gotoxy". "gotoxy" simply moves the cursor so that anything I type start there. So my question is really is there a way to write to the screen without using the cursor.
  • : Okay but how to write the multithreading so that it can get x and y?
    :
    : Oh and also you know of anyother way to write to the dos-screen
    : without using "gotoxy". "gotoxy" simply moves the cursor so that
    : anything I type start there. So my question is really is there a way
    : to write to the screen without using the cursor.
    :
    Local variables are always thread safe. If you call the safe_gotoxy(), then you've a thread-safe gotoxy().
    It is possible to directly place characters and colors into the screen memory. I don't have the code anymore, but have seen it happen.
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories