Modify

Ticket #5351 (closed Patches: fixed)

Opened 3 years ago

Last modified 2 years ago

interrupt a future get boost::unknown_exception

Reported by: qiaozhiqiang@… Owned by: viboes
Milestone: Boost 1.50.0 Component: thread
Version: Boost 1.46.0 Severity: Problem
Keywords: thread interrupt future unknown_exception Cc: viboes

Description

It may be a bug of the thread or future.

in
boost_1_46_0/doc/html/thread/synchronization.html  

it says:
these Member functions:
shared_future class template:
Member function get()
Member function wait()
Member function timed_wait()
and
unique_future class template:
Member function get()
Member function wait()
Member function timed_wait()

Throws: 
........   
boost::thread_interrupted if the result associated with *this is not
 ready at the point of the call, and the [current] thread 
is interrupted.
............ 


but it throws boost::unknown_exception.
and the [current] thread is interrupted.
Should be
the [working] thread is interrupted ?

 > > [Windows XP, VC++ 10, boost 1.46]
> > When interrupt a future, the future.get() throw boost::unknown_exception,
> > Not boost::thread_interrupted.
> >
> > Class boost::thread_interrupted should have a base class for
> > current_exception_impl() to catch it ? or use BOOST_THROW_EXCEPTION to throw ? 
//////////

namespace boost
{

    class thread_interrupted
    {};
}

These function use [ throw thread_interrupted(); ] :
this_thread ::interruption_point() // pthread / win32
this_thread::interruptible_wait()  // win32
interruption_checker:: check_for_interruption()// pthread
/////////////


// [Windows XP, VC++ 10, boost 1.46]
#include <boost/thread.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/thread/future.hpp> 
using namespace boost::posix_time;
using namespace boost; 

int foo()
{
	this_thread::sleep(seconds(1000)); 
	return 0;
}


int main(int argc, char** argv)
{ 
	boost::packaged_task<int> pt(&foo);


	boost::unique_future<int> fi = pt.get_future(); 
	boost::thread task(std::move(pt)); // launch task on a thread 
	
	task.interrupt();  

	try
	{		
		int v = fi.get();	
	} 
	catch (boost::exception& exc)
	{		
		std::cerr << "ERROR: " << boost::diagnostic_information(exc) << std::endl;
	}
}


> >
> > // unknown_exception//////////////////
> > ERROR: Throw in function (unknown)
> > Dynamic exception type: class boost::exception_detail::clone_impl<class
> > boost::unknown_exception>
> > std::exception::what: Unknown exception


Attachments

5351.diff Download (2.9 KB) - added by viboes 2 years ago.
a possible solution
test_5351.cpp Download (914 bytes) - added by viboes 2 years ago.
The adapted test
detail_move.hpp.diff Download (602 bytes) - added by viboes 2 years ago.

Change History

comment:1 Changed 2 years ago by viboes

  • Cc viboes added
  • Owner changed from anthonyw to viboes
  • Status changed from new to assigned
  • Summary changed from [boost::thread] interrupt a future get boost::unknown_exception to interrupt a future get boost::unknown_exception

Changed 2 years ago by viboes

a possible solution

comment:2 Changed 2 years ago by viboes

I have reached to compile the example with some variants.

It seems the problem comes from the fact that packaged_task catch every exception and store it to rethrow in the wait() function using boost::rethrow_exception. As thread_interrupted doesn't inherits from std/boost::exception the throw exception is unknown_exception.

                if(rethrow && exception)
                {
                    boost::rethrow_exception(exception);
                }

A solution could be to catch specifically thread_interrupted and store this fact.

When wait is called, a test if the thread has been interrupted is done so that the exception thread_interrupted is thrown. The single problem is that the this new exception doesn't contains from where the initial thread_interrupted was thrown.

See the attached patch for the complete solution.

Changed 2 years ago by viboes

The adapted test

comment:3 Changed 2 years ago by viboes

There is also another patch that needs to be applied. See detail/move.hpp.diff file.

Changed 2 years ago by viboes

comment:4 Changed 2 years ago by viboes

  • Type changed from Bugs to Patches

comment:5 Changed 2 years ago by viboes

  • Milestone changed from To Be Determined to Boost 1.49.0

comment:6 Changed 2 years ago by viboes

Committed in trunk at revision [76543]. However the issue seems to be also on Windows platforms.

comment:7 Changed 2 years ago by anonymous

catch (boost::thread_interrupted& exc)

if the caller of fi.get() is a boost::thread and is interrupted, get() will throw thread_interrupted. but the future is interrupted now, not the caller. so I recommend get() throw a new class boost::future_interrupted use BOOST_THROW_EXCEPTION.

15	
16	int main(int argc, char** argv)
17	{
18	  boost::packaged_task<int> pt(&foo);
19	  boost::unique_future<int> fi = pt.get_future();
20	  boost::thread task(boost::move(pt)); // launch task on a thread
21	
22	  task.interrupt();
23	
24	  try
25	  {
26	    int v = fi.get();
27	  }
28	  catch (boost::thread_interrupted& exc)
29	  {
30	    std::cout << "OK: " << std::endl;
31	    return 0;
32	  }
33	  catch (boost::exception& exc)
34	  {
35	    std::cout << __LINE__ << " ERROR: " << boost::diagnostic_information(exc) << std::endl;
36	    return 1;
37	  }
38	  catch (...)
39	  {
40	    std::cout << __LINE__ << " ERROR: " << std::endl;
41	    return 2;
42	  }
43	  std::cout << __LINE__ << " ERROR: " << std::endl;
44	  return 3;
45	}

comment:8 Changed 2 years ago by viboes

  • Status changed from assigned to closed
  • Resolution set to fixed
  • Milestone changed from Boost 1.49.0 to Boost 1.50.0

Committed in release branch at [78543]

View

Add a comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
The resolution will be deleted. Next status will be 'reopened'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.