Intel® oneAPI DPC++/C++ Compiler
Talk to fellow users of Intel® oneAPI DPC++/C++ Compiler and companion tools like Intel® oneAPI DPC++ Library, Intel® DPC++ Compatibility Tool, and Intel® Distribution for GDB*
789 Discussions

Crash at exec when compiled with intel c++ 2005 compiler while no issue with microsoft's compiler

Olórin
Novice
3,265 Views

I have coded a custom concurrent queue class and a thread pool class based on it. I have an "advisor" class that I use to expose the Threadpool class (mixed with other functionalities) to more high level code. (These other functionalities are not included as they are not even the ones triggering the crash.)

 

The code for the concurrent queue is in the header "concurrent_queue.h" :

 

#ifndef CONCURRENT_QUEUE_H
#define CONCURRENT_QUEUE_H


#include <queue>
#include <mutex>
#include <optional>

template <class T>
class concurrent_queue
{
    std::queue<T> queue_;
    std::mutex mutex_;
    std::condition_variable cv_;
    bool interrupt_;

public:

    concurrent_queue() : interrupt_(false) {}

    //  Pop into argument
    std::optional<T> try_pop()
    {
        std::optional<T> result;
        //  Lock
        std::lock_guard<std::mutex> lok(mutex_);
        if (!queue_.empty())
        {
            //  Move from queue
            result = move(queue_.front());
            //  Combine front/pop
            queue_.pop();
        }
        return result;
    }

    //  Pass t byVal or move with push( move( t))
    void push(T t)
    {
        {
            //  Lock
            std::lock_guard<std::mutex> lk(mutex_);
            //  Move into queue
            queue_.push(move(t));
        }   //  Unlock before notification

        //  Unlock before notification 
        cv_.notify_one();
    }

    //  Wait if empty
    std::optional<T> pop()
    {
        std::optional<T> result;
        //  (Unique) lock
        std::unique_lock<std::mutex> lk(mutex_);
        //  Wait if empty, release lock until notified 
        cv_.wait(lk, [&] { return interrupt_ || !queue_.empty(); });
        //  Re-acquire lock, resume 

        //  Check for interruption
        if (!interrupt_) {
            result = std::move(queue_.front());
            queue_.pop();
        }
        return result;
    }// Unlock

    void interrupt()
    {
        {
            std::lock_guard<std::mutex> lk(mutex_);
            interrupt_ = true;
        }
        cv_.notify_all();
    }

    void reset_interrupt()
    {
        interrupt_ = false;
    }

    void clear()
    {
        std::queue<T> empty;
        swap(queue_, empty);
    }
};


#endif//CONCURRENT_QUEUE_H

 

and the one for the thread pool is in the header "ThreadPool.h" :

 

#ifndef THREAD_POOL_H
#define THREAD_POOL_H

#include <future>
#include <thread>
#include "concurrent_queue.h"
#include <chrono>



class ThreadPool
{
public:
    using Task = std::packaged_task<bool(void)>;
    using TaskHandle = std::future<bool>;
private:
    //  The one and only instance
    static ThreadPool instance_;
    //  The task queue
    concurrent_queue<Task> concurrent_queue_;
    //  The threads
    std::vector<std::thread> threads_;
    //  Active indicator
    bool is_active_;
    //  Interruption indicator
    bool interrupt_;
    //  Thread number
    static thread_local size_t my_tls_num_;

    //  The function that is executed on every thread
    void threadFunc(const size_t num)
    {
        my_tls_num_ = num;
        //  "Infinite" loop, only broken on destruction
        while (auto t = concurrent_queue_.pop())
        {
            (*t)();
        }
    }

    //  The constructor stays private, ensuring single instance
    ThreadPool() : is_active_(false), interrupt_(false) {}

public:
    //  Access the instance
    static ThreadPool* getInstance() { return &instance_; }
    //  Number of threads
    size_t numThreads() const { return threads_.size(); }
    //  The number of the caller thread
    static size_t threadNum() { return my_tls_num_; }
    //  Starter
    void start(const size_t nThread = std::thread::hardware_concurrency() - 1)
    {
        if (!is_active_)  //  Only start once
        {
            threads_.reserve(nThread);

            //  Launch threads on threadFunc and keep handles in a vector
            for (size_t i = 0; i < nThread; i++)
                threads_.push_back(std::thread(&ThreadPool::threadFunc, this, i + 1));

            is_active_ = true;
        }
    }
    //dtor
    ~ThreadPool()
    {
        stop();
    }
    void stop()
    {
        if (is_active_)
        {
            //  Interrupt mode
            interrupt_ = true;
            //  Interrupt all waiting threads
            concurrent_queue_.interrupt();
            //  Wait for them all to join
            for_each(threads_.begin(), threads_.end(), std::mem_fn(&std::thread::join));
            //  Clear all threads
            threads_.clear();
            //  Clear the queue and reset interrupt
            concurrent_queue_.clear();
            concurrent_queue_.reset_interrupt();
            //  Mark as inactive
            is_active_ = false;
            //  Reset interrupt
            interrupt_ = false;
        }
    }
    //  Forbid copies etc
    ThreadPool(const ThreadPool& rhs) = delete;
    ThreadPool& operator=(const ThreadPool& rhs) = delete;
    ThreadPool(ThreadPool&& rhs) = delete;
    ThreadPool& operator=(ThreadPool&& rhs) = delete;
    //  Spawn task
    template<typename Callable>
    TaskHandle spawnTask(Callable c)
    {
        Task t(std::move(c));
        TaskHandle f = t.get_future();
        concurrent_queue_.push(std::move(t));
        return f;
    }

    //  Run queued tasks synchronously 
    //  while waiting on a future, 
    //  returns true if at least one task was run
    bool activeWait(const TaskHandle& f)
    {
        using namespace std::chrono_literals;
        bool b = false;
        //  Check whether or not the future is ready without blocking
        //  by waiting 0 seconds and returning status
        while (f.wait_for(0s) != std::future_status::ready)
        {
            //  Non blocking
            if (auto t = concurrent_queue_.try_pop())
            {
                (*t)();
                b = true;
            }
            else // Nothing in the queue: go to sleep
            {
                f.wait();
            }
        }
        return b;
    }
};

inline ThreadPool ThreadPool::instance_;
inline thread_local size_t ThreadPool::my_tls_num_ = 0;



#endif//THREAD_POOL_H

 

The code for the Advisor class is in the heard "Advisor.h" :

 

#ifndef ADVISOR_H
#define ADVISOR_H

#include <mutex>
#include "ThreadPool.h"


class Advisor
{
private:
    static Advisor * pinstance_;
    static std::mutex mutex_;
protected:
    Advisor(const size_t nThread = std::thread::hardware_concurrency() - 1)
    {
        ThreadPool::getInstance()->start(nThread);
    }
    virtual  ~Advisor()
    {
        ThreadPool::getInstance()->stop();
    }
public:
    Advisor(const Advisor& rhs) = delete;
    Advisor& operator=(const Advisor& rhs) = delete;
    Advisor(Advisor&& rhs) = delete;
    Advisor& operator=(Advisor&& rhs) = delete;

    static Advisor* GetInstance(const size_t nThread = std::thread::hardware_concurrency() - 1);
};

/**
 * Static methods should be defined outside the class.
 */
Advisor* Advisor::pinstance_{ nullptr };
std::mutex Advisor::mutex_;

/**
 * The first time we call GetInstance we will lock the storage location
 *      and then we make sure again that the variable is null and then we
 *      set the value. RU:
 */
Advisor* Advisor::GetInstance(const size_t nThread)
{
    std::lock_guard<std::mutex> lock(mutex_);
    if (pinstance_ == nullptr)
    {
        pinstance_ = new Advisor(nThread);
    }
    return pinstance_;
}






#endif//ADVISOR_H

 

and finally the "client" code is :

 

#include <iostream>
#include "Advisor.h"

static Advisor* pricingAdvisorSingleton = Advisor::GetInstance();

int main()
{
    std::cout << "Ok!\n";
}

 

The coded I attach is a zipped visual studio 2022 professional C++ console app solution folder. The solution compiles fine with intel 2025 (or even 2024) C++ compiler but doesn't execute properly. It crashes on the line

threads_.push_back(std::thread(&ThreadPool::threadFunc, this, i + 1));

from the "ThreadPool.h" header, triggered by the third line from the Advisor hearder.

 

Switching the compiler to the latest microsoft's compiler, the solution does compile and execute properly (as everything multi-threaded (or not based) on it).

 

The project configuration can be seen in the vcxproj file, but I nevertheless put it beneath for sake of conveniance :

 

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Debug|x64">
      <Configuration>Debug</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|x64">
      <Configuration>Release</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <VCProjectVersion>17.0</VCProjectVersion>
    <Keyword>Win32Proj</Keyword>
    <ProjectGuid>{7dfba301-3902-46a0-9386-e922834c2279}</ProjectGuid>
    <RootNamespace>ConsoleApplication1</RootNamespace>
    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>Intel C++ Compiler 2025</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>Intel C++ Compiler 2025</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings">
  </ImportGroup>
  <ImportGroup Label="Shared">
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <PropertyGroup Label="UserMacros" />
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <LanguageStandard>stdcpplatest</LanguageStandard>
      <AdditionalIncludeDirectories>$(MYINTEL_INCLUDE)</AdditionalIncludeDirectories>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <AdditionalLibraryDirectories>$(MYINTEL_LIB)</AdditionalLibraryDirectories>
      <AdditionalDependencies>mkl_intel_lp64.lib;;mkl_core.lib;mkl_rt.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <LanguageStandard>stdcpplatest</LanguageStandard>
      <AdditionalIncludeDirectories>$(MYINTEL_INCLUDE)</AdditionalIncludeDirectories>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <AdditionalLibraryDirectories>$(MYINTEL_LIB)</AdditionalLibraryDirectories>
      <AdditionalDependencies>mkl_intel_lp64.lib;;mkl_core.lib;mkl_rt.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup>
    <ClCompile Include="ConsoleApplication1.cpp" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="concurrent_queue.h" />
    <ClInclude Include="Advisor.h" />
    <ClInclude Include="ThreadPool.h" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
  </ImportGroup>
</Project>

 

where MYINTEL_INCLUDE and MYINTEL_LIB are system environment variables pointing respectively to C:\Program Files (x86)\Intel\oneAPI\mkl\latest\include and C:\Program Files (x86)\Intel\oneAPI\mkl\latest\lib

 

What do I do wrong relatively to the intel compiler explaining the crash ?

0 Kudos
4 Replies
yzh_intel
Moderator
2,898 Views

Hi, I found that the issue will disappear in release mode or replace the option /MDd with /MD in debug mode, could you confirm if this is a valid workaround on your side ? I also escalated the issue to compiler team, and will get back once there's any updates

0 Kudos
Olórin
Novice
2,356 Views

Hi and thank you for your answer. I don't understand what you mean with "I found that the issue will disappear in release mode or replace the option /MDd with /MD in debug mode". You mean in debug mode the issue disappears would the option /MDd be replaced with /MD, correct ? But what do you mean for release mode ?

0 Kudos
yzh_intel
Moderator
2,139 Views

Right, I don't see the issue in release mode where /MD is default, could you also verify if this works?

0 Kudos
yzh_intel
Moderator
1,505 Views

Hi, Here's another workaround that you can move the global statics to functional local statics as follows, please try to verify on your end.

static ThreadPool* getInstance() {  static ThreadPool instance_; return &instance_; }

 

0 Kudos
Reply