0

The title pretty much summarizes what my problem is. I have this function shown below and when I press the button to join the thread the application stops responding. I'm fairly new to multithreading in c++ and I don't really know what I am doing or why this is occurring.

HWND hwnd;
//this stops the declaration of the thread from saying that hwnd doesn't exist
bool stopRaidAction;

void JoinLoop(HWND hwnd)
{
    for (std::string tokenString; std::getline(std::cin,tFileContents,'\n');) {
        if(stopRaidAction==false)
        {
            if(tokenString.length()==0){break;}
            if(tokenString.length()!=0){
                //send post request to join the server using token through proxy
            }
        }
        if(stopRaidAction){break;}
    }
}

std::thread joinThread(JoinLoop, hwnd);

The issue is with the "JOIN_RAID" thing

LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM param, LPARAM lparam) {
    switch (msg) {
    case WM_CREATE:
        Controls(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_COMMAND:
    {
        if ((HIWORD(param) == BN_CLICKED) && (lparam != 0))
        {
            switch (LOWORD(param))
            {
                case JOIN_RAID:
                    stopRaidAction=false;
                    MessageBeep(MB_OK);
                    joinThread.join();
                    break;

                case STOP_RAID:
                    stopRaidAction=true;
                    MessageBeep(MB_OK);
                    break;
            }
        }
        break;
    }
    default:
        return DefWindowProc(hwnd, msg, param, lparam);
    }
    return 0;
}
  • 1
    `stopRaidAction` is not `atomic`, so you have a data race (one thread reading and another writing without synchronization), which is undefined behavior. Hanging is a valid manifestation of undefined behavior. – Raymond Chen Feb 06 '21 at 17:26
  • 1
    @Supergamer5465: It also looks like maybe in the case where you join the thread, you never trigger the termination condition for the loop in the thread function. – scg Feb 06 '21 at 17:29
  • I made it atomic, but it still hangs. How could I trigger this "termination condition"? –  Feb 06 '21 at 19:39

2 Answers2

1

joinThread.join() blocks the calling thread until JoinLoop() exits. If you do that call in your main UI thread, you will be blocking your message loop from being able to process new messages. That is why your UI freezes.

JoinLoop() is waiting on 2 conditions - user input being entered, and stopRaidAction being true while processing that input. Even if the user enters input, your main thread is setting stopRaidAction to false before calling join(), so unless JoinLoop() itself, or a 3rd thread, sets stopRaidAction to true then JoinLoop() won't exit, and so join() won't unblock.

Even if stopRaidAction were able to be set to true while join() is waiting, JoinLoop() still won't exit until the next time that user input is entered, so it can see the new stopRaidAction value. There is no way to unlocking a pending std::getline() call. So you should rewrite the way you are handling console input so you can stop waiting for input in a timely manner. See Win32 - read from stdin with timeout, for instance.

std::thread::join() is not something you should be calling until you are ready to terminate the worker thread. Which this code is not doing.

Given the code shown, it may make more sense to not create the thread at all until JOIN_RAID is clicked, and then terminate the thread when `STOP_RAID' is clicked, eg:

bool stopRaidAction = false;
std::thread joinThread;

void JoinLoop(HWND hwnd)
{
    std::string tokenString;
    while (!stopRaidAction) {
        // read input with timeout...
        if(tokenString.empty()){ break; }
        //send post request to join the server using token through proxy
    }
}

LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM param, LPARAM lparam) {
    switch (msg) {
    case WM_CREATE:
        Controls(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_COMMAND:
    {
        if ((HIWORD(param) == BN_CLICKED) && (lparam != 0))
        {
            switch (LOWORD(param))
            {
                case JOIN_RAID:
                    stopRaidAction=false;
                    MessageBeep(MB_OK);
                    joinThread = std::thread(JoinLoop, hwnd);
                    break;

                case STOP_RAID:
                    stopRaidAction=true;
                    MessageBeep(MB_OK);
                    if (joinThread.joinable()) joinThread.join();
                    break;
            }
        }
        break;
    }
    default:
        return DefWindowProc(hwnd, msg, param, lparam);
    }
    return 0;
}

But this is just speculation since you did not explain what you are actually trying to achieve in the first place.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

Update:

IT WAS THE FOR LOOP. I am literally dying. I don't even know how many hours I spent debugging only to find out that the for loop was messed up and causing the hangs.

  • Please post the fixed code and explain what was wrong with the old code and how the fix addresses it. This is a collaborative site, and the next person with this problem would like to see the solution. – Raymond Chen Feb 21 '21 at 14:07