c++exceptionboostembedded-linux

boost::thread::try_join_for throwing invalid argument [generic:22] after upgrading boost from 1.48 to 1.88


I am using an embedded linux (Yocto project) and recently upgraded to the latest boost version. The compiler used is arm-poky-linux-gnueabi-g++ (GCC) 13.3.0

The problem I am facing can be reproduced by this little code piece, what I assume is valid code.

    boost::thread t([](){ std::this_thread::sleep_for(std::chrono::seconds(5)); });
    try
    {
        std::cout << BOOST_VERSION << std::endl;
#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
        std::cout << "THROW_IF_ ... is defined" << std::endl;
#else
        std::cout << "THROW_IF_ ... is not defined" << std::endl;
#endif
        std::cout << "try join for " << std::endl;
        if(t.try_join_for(boost::chrono::milliseconds(500)))
            std::cout << "done" << std::endl;
        std::cout << "after tjf " << std::endl;
    }
    catch(const std::exception& e)
    {
        std::cout << e.what() << std::endl;
    }

    t.join();

    return 0;

The output on my embedded system, where the exception occurs and was working before upgrade to boost v1.88, is:

108800
THROW_IF_ ... is not defined
try join for
boost::condition_variable::do_wait_until failed in pthread_cond_timedwait: Invalid argument [generic:22]

Whereas the output in a Ubuntu 24.04.2 LTS is:

108300
THROW_IF_ ... is not defined
try join for
after tjf 

I checked that I don't accidentally compile against 1.88 and using an older version of the shared lib at runtime as @sehe stated. In fact, there actually were some older versions of the library present, which I have deleted. Still the same behavior.

Of course I can revise the code and make it work again, but I really would like to know what is happending. Maybe I have overlooked something? Help is much appreciated.

EDIT 1: What I have tried is to define the following directives, recompile the whole project and solved all compile errors, but the exception still occurs.

BOOST_THREAD_USES_CHRONO=1 BOOST_THREAD_DONT_USE_DATETIME 1 BOOST_ALLOW_DEPRECATED 0

I changed std::this_thread::sleep_for to boost::this_thread::sleep_for

Strange thing is, if I replace this line

if(t.try_join_for(boost::chrono::milliseconds(500)))

by that line

if(t.joinable() && t.try_join_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(500)))

no exception is thrown, however, try_join_until does not return after 500ms, but after 5secs.

EDIT 2: I followed the problem to https://github.com/boostorg/thread/blob/boost-1.88.0/include/boost/thread/pthread/condition_variable.hpp and I am pretty sure the exception arises in line 139 which means this call fails:

cond_res=posix::pthread_cond_timedwait(&cond,the_mutex,&timeout.getTs());

I assume cond and the_mutex is properly initialized, which means timeout.getTs() is the problem. Using strace the last output before the exception is caught is

clock_gettime64(CLOCK_MONOTONIC, {tv_sec=66290, tv_nsec=902644605}) = 0

I tried a small example using pthread_cond_timedwait where I don't use boost but all function from std which works fine.

My conclusion is, that there must be some setting, define, system dependent problem with my system.


Solution

  • I think the problem was, that the boost library was built using 64 bit time value. (struct timespec)

    And when compiling my application against this library it was built using 32 bit time value.

    Unfortunately I can not tell 100% what / where exactly it happened, but I imagine a 64 bit value was assigned to a 32 bit value which led to a negative value as timespec.tv_usec parameter for pthread_cond_timedwait.

    Using _TIME_BITS=32 when compiling boost respectively _TIME_BITS=64 when compiling the application solves the problem.

    FYI: According to gnu.org _FILE_OFFSET_BITS has to be set if _TIME_BITS is used.