std::thread unable to create a thread on a small number of systems

Kris 6 Reputation points
2022-09-01T20:47:50.93+00:00

A few months ago, we started receiving reports from a relatively small number of customers who cannot use our application due to it crashing immediately. This has started to affect a growing number of users by now but we still do not see a clear pattern between users. Upon investigation, any executable component of our application appears to be crashing immediately when trying to launch any thread (all are using std::thread).

Exception handling is disabled. std::thread appears to throw an exception from std::thread::_Start with _Throw_Cpp_error(_RESOURCE_UNAVAILABLE_TRY_AGAIN) because the prior call to _beginthreadex apparently failed. The immediate crash is due to the lack of exception handling, but even if we would enable exception handling, threads aren't optional for us so we need to solve the underlying problem.

We are using:

  • Visual Studio 2022 Professional 17.3.3 but this has been going on for months with many older versions that I cannot list now.
  • Windows SDK 22000 and 22621.
  • MSVC C++ 17 and 20, static runtime.

We didn't release any updates around the time the first reports of this issue appeared, so it seems likely that the issue is not related to any changes in our build environment. Furthermore, we had a few quiet weeks now, but in the recent 24 hrs we got a dozen new customers with this issue without us making any changes, so it seems very likely that a Windows update is partially responsible and these customers just got it installed through a rolling release.

The issues occur for Windows 10 and 11 users, using both 32-bit and 64-bit builds of the application. We have not been able to identify a reliable pattern of software, drivers, lack of updates or other circumstances. The issue does not occur for a majority of users nor on any of our computers, but for the people that are experiencing the issue, it is quite persistent and immediate and renders our application completely unusable.

In the last confirmed case of this, the user reported that reinstalling their Windows 11 temporarily fixed the issue - until they installed Windows updates and it started to occur again.

What could we do in order to solve this? Is there any other information we can provide or sensible questions we could forward to affected users?

Windows 10
Windows 10
A Microsoft operating system that runs on personal computers and tablets.
11,575 questions
Windows 11
Windows 11
A Microsoft operating system designed for productivity, creativity, and ease of use.
9,603 questions
{count} vote

3 answers

Sort by: Most helpful
  1. RLWA32 45,476 Reputation points
    2022-09-03T23:04:35.17+00:00

    One of the main roadblocks seems to be that the actual Windows error code set when CreateThread fails is lost. The exception thrown is not informative.

    I copied the thread header to a test project source folder and made a few small changes to it so that if _beginthreadex returns 0 the function throws the Windows error code as an exception. A sample console application uses quotes instead of angle brackets when including the header so as to build with the altered copy.

    In a proof of concept console application (must be a 32-bit build) I deliberately altered the call to _beginthreadex to use an invalid parameter and force an error return. Your version wouldn't include this alteration.

    from thread header -

            _Thr._Hnd =  
                reinterpret_cast<void*>(_CSTD _beginthreadex(nullptr, /*32-bit build cause invalid parameter error */ UINT32_MAX, _Invoker_proc, _Decay_copied.get(), 0, &_Thr._Id));  
    #pragma warning(pop)  
      
            if (_Thr._Hnd) { // ownership transferred to the thread  
                (void) _Decay_copied.release();  
            } else { // failed to start thread  
                unsigned long errorCode{};  
                _get_doserrno(&errorCode); // Get error code from CreateThread  
                throw errorCode;  
                _Thr._Id = 0;  
                _Throw_Cpp_error(_RESOURCE_UNAVAILABLE_TRY_AGAIN);  
            }  
    

    Once again, the site choked on a code post so the proof of concept console app is an image -

    237480-poc.png

    At least with this you might get some diagnostic info from a customer experiencing the problem.

    1 person found this answer helpful.

  2. Limitless Technology 39,611 Reputation points
    2022-09-06T07:21:26.183+00:00

    Hello

    Thank you for your question and reaching out. I can understand you are having issues related to your Application.

    It may be due to Recent Security updates in Windows 10 or 11 , Please try to Uninstall any Recent updates applied on Windows.

    Also , Please try to Debug or Remote Debug the application to have complete Exception with .DLL or which component raising this error.

    Disable any Antivirus program or Windows firewall you may have for temporary purpose.

    ----------------------------------------------------------------------------------------------------------------------------------------

    --If the reply is helpful, please Upvote and Accept as answer--


  3. sFrance41 1 Reputation point
    2022-10-18T10:03:53.303+00:00

    Raised thread error with our own application (source code herebelow) , trap into the call to _beginthreadex .
    but can not provide errno since protection prevent from modifying VC thread file.

    Microsoft Visual Studio Professional 2019 Version 16.11.20
    VisualStudio.16.Release/16.11.20+32929.386
    Microsoft .NET Framework Version 4.8.04084
    Version installée : Professional
    Microsoft Visual C++ 2019 00435-20050-35417-AA319
    System Windows 10 professional build 19041.1415

    pragma once

    include <functional>

    include <chrono>

    include <mutex>

    include <map>

    include <thread>

    using namespace std;

    template<class callable>
    class timerHandler
    {
    public:
    template <class timerevent>
    timerHandler(int timerId, long after, timerevent* pclass, void (timerevent::* f) (int))
    {
    m_pobjects<timerevent>[timerId] = pclass;
    m_pmemfuncs<timerevent>[timerId] = f;
    m_period = after;
    m_timerId = timerId;
    wakeup = true;
    }

    template <class timerevent>  
    void start()  
    {  
        std::this_thread::sleep_for(std::chrono::milliseconds(m_period));  
        long cr = WaitForSingleObject(runningtimers_mutex, INFINITE);  
        if (wakeup == true)  
            (m_pobjects<timerevent>[m_timerId]->*m_pmemfuncs<timerevent>[m_timerId])(m_timerId);  
        runningtimers_map<callable>.erase(m_timerId);  
        cr = ReleaseMutex(runningtimers_mutex);  
    }  
    
    void stop(void)  
    {  
        wakeup = false;  
    }  
    
    long m_period;  
    int m_timerId;  
    bool wakeup;  
    

    };

    template <class timerevent>
    static map <int, timerevent*> m_pobjects;

    template <class timerevent>
    static map <int, void (timerevent::*)(int)> m_pmemfuncs;

    template<class callable>
    static std::map <int, timerHandler <callable>*> runningtimers_map;

    static HANDLE runningtimers_mutex;

    template<class callable>
    class C_Timer {
    public:
    C_Timer()
    {}

    void stop(int timerId)  
    {  
        long cr = WaitForSingleObject(runningtimers_mutex, INFINITE);  
        if (runningtimers_map <callable>.count(timerId) == 1)  
            runningtimers_map <callable>[timerId]->stop();     
        cr = ReleaseMutex(runningtimers_mutex);  
    }  
    
    /////////////////////////////////////////////  
    //  
    //    start  
    //    lance le timer pour une durée de after ms  
    //    sur timer échu, appelle la fonction void (callable::*f) (int) désigné par la classe template    
    //    callable* pclass  
    //   
    /////////////////////////////////////////////  
    template <class timerevent>  
    int start(int after, timerevent* pclass, void (timerevent::* f) (int))  
    {  
        if (runningtimers_mutex == nullptr)  
            runningtimers_mutex = CreateMutex(NULL, FALSE, NULL);  
    
        long cr = WaitForSingleObject(runningtimers_mutex, INFINITE);  
    
        auto iter = runningtimers_map <callable>.begin();  
        int i = 0;  
        for (; iter != runningtimers_map <callable>.end(); iter++)  
        {  
            if (iter->second == nullptr)  
            {  
                m_timerId = i; break;  
            }  
            else  
                i++;  
        }  
    
        if (iter == runningtimers_map<callable>.end())  
            m_timerId = i;  
    
        m_ptimerHdl = new timerHandler <callable>(m_timerId, after, pclass, f);  
        if (iter == runningtimers_map<callable>.end())  
        {  
            runningtimers_map<callable>.insert({ i, m_ptimerHdl });  
        }  
        else  
        {  
            runningtimers_map<callable>[i] = m_ptimerHdl;  
        }  
    
        thread t(&timerHandler <callable> ::start<timerevent>, m_ptimerHdl);                                       << trap here somtimes>>  
        t.detach();  
    
        cr = ReleaseMutex(runningtimers_mutex);  
        return i;  
    }  
    

    private:
    timerHandler <callable>* m_ptimerHdl;
    int m_timerId;
    };

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.