简体   繁体   中英

C++ multithreaded program work fine in windows, throws "resource temporarily unavailable" in Linux

Edit:

Based on Jonathan's comment, I tried to create a standalone program to reproduce this issue. I was unable to recreate the issue.

Then I switched to Jeremy's comment to make sure I really am calling this only once. Turns out, there was a bug in the upstream code which was calling this in a loop when a specific condition was met.

My first instinct was to have a flag before the thread create to check if it has been already created for the given dayIndex. Like

    if (threadSpawnedForEachDay[dayIndex]) {
        return;
    }

Which took care of the "resource temporarily unavailable", but the output was still buggy. It took me a full 2 days to debug because I could only reproduce the behavior in Linux release build after 30 minutes. ( it has recursive logic and the bug shows up something like 100 calls deep ).

My original post

I have a simple 2 threaded logic implemented in C++

  • A thread which sleeps for a limited time, and then flips a switch
  • A main thread that does everything. It checks the switch periodically, and when it's flipped it knows to wrap up and exit gracefully

The program runs fine in Windows, but in Linux (Ubuntu 20.04) it eventually throws a system error: "Resource temporarily unavailable". I tried htop on Linux, and it appears that the program is creating threads uncontrollably. What could be causing this?

Here's my header:

    struct TimeHelper {
        std::atomic_bool *timerForEachDay;
        std::vector<std::chrono::seconds> startTimeVector;
        bool isTimeUp(int dayIndex);
        void setStartTime(int dayIndex);
        void timerThread(int dayIndex);
        TimeHelper();
        ~TimeHelper();
        void TimeHelperInitializer();
    };
    extern TimeHelper timer;

Here's the code: some values hard coded here for brevity - my actual code uses a configuration file

TimeHelper timer;

TimeHelper::TimeHelper() {
    timerForEachDay = NULL;
}

TimeHelper::~TimeHelper() {
    delete[] timerForEachDay;
}

//Separate initializer because the constructor is run before main
//This is only called once
void TimeHelper::TimeHelperInitializer() {
    timerForEachDay= new std::atomic_bool[2];
    for (int i = 0; i < 2; i++) {
        timerForEachDay[i]=false;
    }
    setStartTime(0); //setStartTime for other days is called elsewhere. It is only called once for each dayIndex at an appropriate time.
    return;
}

bool TimeHelper::isTimeUp(int dayIndex) {
    if (timerForEachDay[dayIndex] == true) return true;
    return false;
}

void TimeHelper::timerThread(int dayIndex) {
    std::this_thread::sleep_for(std::chrono::seconds(20));
    timerForEachDay[dayIndex] = true;
}

void TimeHelper::setStartTime(int dayIndex) {
    std::thread th(&TimeHelper::timerThread, this, dayIndex);
    th.detach();
    return;
}

Turns out there was a bug in the upstream code which was making repeated calls to setStartTime.

The reason why the issue showed up only in Linux is because it is a much faster OS. Windows would probably have the same experience if I let the code run for a few days. ( in case anyone's curious, the program tries to find the "best fit" for a given amount of time but if not available then switches to look for "a good enough fit" ).

Thank you to everyone who commented on my question. Your comments steered me in the right direction.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM