Intel® oneAPI Threading Building Blocks
Ask questions and share information about adding parallelism to your applications when using this threading library.

TBB Crashes trying to set MXCSR

foxtoxer
Beginner
1,778 Views

I have the latest version of TBB from github, it is not modified.

Windows version, x64, compiled with VS2017 using the tbb provided solution.

Most of the time when I boot my application it will crash on startup as one of the spawned threads attempts to set  the MXCSR.

The error is access violation reading 0xFFFFFFFF. 

I checked the dissassembly, and it is the instruction LDMXCSR  that crashes.

 

At line 418 of custom_scheduler.h: 

context_guard.set_ctx( __TBB_CONTEXT_ARG1(t->prefix().context) );

 

This invokes set_env: line 242 of msvc_ia32_common.h

Which calls __TBB_set_cpu_ctl_env

And crashes.

 

It does not crash every time, probably around 85% it crashes.

 

I "fixed" it by removing this line: context_guard.set_ctx( __TBB_CONTEXT_ARG1(t->prefix().context) );

And not setting the MXCSR

 

0 Kudos
7 Replies
Alexei_K_Intel
Employee
1,778 Views

What TBB interfaces do you use? Do you use the enqueue interface?

0 Kudos
foxtoxer
Beginner
1,778 Views

I do use enqueue fairly heavily(most of my tasks use it over spawn)

Other stuff I use:

-spawn(very rarely)

-flow graph(but I think the crash happens before it comes online)

 

-lots of uses of spin_mutex/mutex/concurrent_queue/concurrent_vector

 

 

0 Kudos
Alexei_K_Intel
Employee
1,778 Views

How do you allocate the tasks for enqueuing? What tbb::task_group_context they reference to? (My supposition is that tbb::task_group_context is destroyed before the enqueued task is finished).

0 Kudos
foxtoxer
Beginner
1,778 Views

Hi Alex,

  I tested it to see what was being enque'd prior to the crash, it shows two tasks, they both use the same code path.

    TBB_Task<task_type>* t = new(tbb::task::allocate_root()) TBB_Task<task_type>(std::move(task));

     tbb::task::enqueue(*t, tbb::priority_normal);

TBB_Task looks like this:

 

template <class Functor> class TBB_Task : public tbb::task {
  Functor _Job;
  tbb::task *execute() final{
     math::disable_denormalized_floating_point();
    _Job();
    return nullptr;
  }
public:
    TBB_Task(Functor &&fxn) : _Job(std::move(fxn)) {}
};

 

(removing the call to disable_denormalized_floating_point doesn't change anything)

0 Kudos
Alexei_K_Intel
Employee
1,778 Views

I am afraid about tbb::task::allocate_root() because it is uses the task_group_context of currently executing task. Do you call it inside some TBB algorithm?

0 Kudos
foxtoxer
Beginner
1,778 Views

Hi Alex,

I checked and yes both of them are being called within a call to tbb::parallel_invoke, they are nested within the same lambda, so they are launched serially when it is invoked. 

I see what you are saying, it is using an expired context from parallel_invoke. 

spawn does not suffer from this I take it? 

(EDIT) nm spawn is worse and doesn't run at all

 

 

 

0 Kudos
Alexei_K_Intel
Employee
1,778 Views

You can use an explicit tbb::task_group_context with tbb::allocate_root to avoid implicit binding to the context of tbb::parallel_invoke. However, my concern is why do you need low level tasking (that has multiple hidden issues like that)? You may want to use task_group or flow graph if you need some sort of asynchronous tasking. 

0 Kudos
Reply