Skip to content

Commit e81982b

Browse files
Exceptions in threads automatically handled
1 parent 4d70fdf commit e81982b

29 files changed

+306
-87
lines changed

doc/release_notes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ OpenPose Library - Release Notes
322322
30. Added pre-processing capabilities to Wrapper (WorkerType::PreProcessing), which will be run right after the image has been read.
323323
31. Removed boost::shared_ptr and caffe::Blob dependencies from the headers. No 3rdparty dependencies left on headers (except dim3 for CUDA).
324324
32. Added Array `poseNetOutput` to Datum so that user can introduce his custom network output.
325+
33. OpenPose will never provoke a core dumped or crash. Exceptions in threads (`errorWorker()` instead of `error()`) lead to stopping the threads and reporting the error from the main thread, while exceptions in destructors (`errorDestructor()` instead of `error()`) are reported with std::cerr but not thrown as std::exceptions.
325326
2. Functions or parameters renamed:
326327
1. By default, python example `tutorial_developer/python_2_pose_from_heatmaps.py` was using 2 scales starting at -1x736, changed to 1 scale at -1x368.
327328
2. WrapperStructPose default parameters changed to match those of the OpenPose demo binary.

examples/tests/wrapperHandFromJsonTest.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ namespace op
111111
}
112112
catch (const std::exception& e)
113113
{
114-
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
114+
errorDestructor(e.what(), __LINE__, __FUNCTION__, __FILE__);
115115
}
116116
}
117117

include/openpose/core/arrayCpuGpu.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ namespace op
6868

6969
const T* cpu_data() const;
7070
void set_cpu_data(T* data);
71-
// const int* gpu_shape() const; // Disabled because it produces compiler errors for some users
71+
const int* gpu_shape() const;
7272
const T* gpu_data() const;
7373
void set_gpu_data(T* data);
7474
const T* cpu_diff() const;

include/openpose/thread/subThread.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ namespace op
143143
try
144144
{
145145
for (auto& tWorker : mTWorkers)
146-
tWorker->initializationOnThread();
146+
tWorker->initializationOnThreadNoException();
147147
}
148148
catch (const std::exception& e)
149149
{

include/openpose/thread/thread.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ namespace op
9696
}
9797
catch (const std::exception& e)
9898
{
99-
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
99+
errorDestructor(e.what(), __LINE__, __FUNCTION__, __FILE__);
100100
}
101101
}
102102

include/openpose/thread/threadManager.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ namespace op
235235
for (auto& thread : mThreads)
236236
thread->stopAndJoin();
237237
log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__);
238+
checkWorkerErrors();
239+
log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__);
238240
}
239241
catch (const std::exception& e)
240242
{
@@ -396,6 +398,9 @@ namespace op
396398
{
397399
if (!mThreadWorkerQueues.empty())
398400
{
401+
// This avoids extra std::cout if errors occur on different threads
402+
setMainThread();
403+
399404
// Check threads
400405
checkAndCreateEmptyThreads();
401406

include/openpose/thread/worker.hpp

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace op
1313

1414
virtual ~Worker();
1515

16-
virtual void initializationOnThread() = 0;
16+
void initializationOnThreadNoException();
1717

1818
bool checkAndWork(TDatums& tDatums);
1919

@@ -35,6 +35,8 @@ namespace op
3535
}
3636

3737
protected:
38+
virtual void initializationOnThread() = 0;
39+
3840
virtual void work(TDatums& tDatums) = 0;
3941

4042
private:
@@ -62,12 +64,35 @@ namespace op
6264
{
6365
}
6466

67+
template<typename TDatums>
68+
void Worker<TDatums>::initializationOnThreadNoException()
69+
{
70+
try
71+
{
72+
this->initializationOnThread();
73+
}
74+
catch (const std::exception& e)
75+
{
76+
this->stop();
77+
errorWorker(e.what(), __LINE__, __FUNCTION__, __FILE__);
78+
}
79+
}
80+
6581
template<typename TDatums>
6682
bool Worker<TDatums>::checkAndWork(TDatums& tDatums)
6783
{
68-
if (mIsRunning)
69-
work(tDatums);
70-
return mIsRunning;
84+
try
85+
{
86+
if (mIsRunning)
87+
work(tDatums);
88+
return mIsRunning;
89+
}
90+
catch (const std::exception& e)
91+
{
92+
this->stop();
93+
errorWorker(e.what(), __LINE__, __FUNCTION__, __FILE__);
94+
return false;
95+
}
7196
}
7297

7398
COMPILE_TEMPLATE_DATUM(Worker);

include/openpose/thread/workerConsumer.hpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@ namespace op
1212
public:
1313
virtual ~WorkerConsumer();
1414

15-
inline void work(TDatums& tDatums)
16-
{
17-
workConsumer(tDatums);
18-
}
15+
void work(TDatums& tDatums);
1916

2017
protected:
2118
virtual void workConsumer(const TDatums& tDatums) = 0;
@@ -34,6 +31,20 @@ namespace op
3431
{
3532
}
3633

34+
template<typename TDatums>
35+
void WorkerConsumer<TDatums>::work(TDatums& tDatums)
36+
{
37+
try
38+
{
39+
workConsumer(tDatums);
40+
}
41+
catch (const std::exception& e)
42+
{
43+
this->stop();
44+
errorWorker(e.what(), __LINE__, __FUNCTION__, __FILE__);
45+
}
46+
}
47+
3748
COMPILE_TEMPLATE_DATUM(WorkerConsumer);
3849
}
3950

include/openpose/thread/workerProducer.hpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@ namespace op
1212
public:
1313
virtual ~WorkerProducer();
1414

15-
inline void work(TDatums& tDatums)
16-
{
17-
tDatums = std::move(workProducer());
18-
}
15+
void work(TDatums& tDatums);
1916

2017
protected:
2118
virtual TDatums workProducer() = 0;
@@ -34,6 +31,20 @@ namespace op
3431
{
3532
}
3633

34+
template<typename TDatums>
35+
void WorkerProducer<TDatums>::work(TDatums& tDatums)
36+
{
37+
try
38+
{
39+
tDatums = std::move(workProducer());
40+
}
41+
catch (const std::exception& e)
42+
{
43+
this->stop();
44+
errorWorker(e.what(), __LINE__, __FUNCTION__, __FILE__);
45+
}
46+
}
47+
3748
COMPILE_TEMPLATE_DATUM(WorkerProducer);
3849
}
3950

include/openpose/utilities/errorAndLog.hpp

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#ifndef OPENPOSE_UTILITIES_ERROR_AND_LOG_HPP
22
#define OPENPOSE_UTILITIES_ERROR_AND_LOG_HPP
33

4-
#include <atomic>
5-
#include <mutex>
64
#include <sstream> // std::stringstream
75
#include <string>
86
#include <vector>
@@ -11,6 +9,14 @@
119

1210
namespace op
1311
{
12+
OP_API void setMainThread();
13+
14+
OP_API std::string getThreadId();
15+
16+
OP_API bool getIfInMainThreadOrEmpty();
17+
18+
OP_API bool getIfNotInMainThreadOrEmpty();
19+
1420
template<typename T>
1521
std::string tToString(const T& message)
1622
{
@@ -21,27 +27,65 @@ namespace op
2127
return oss.str();
2228
}
2329

30+
/**
31+
* Differences between different kind of errrors:
32+
* - error() is a normal error in the code.
33+
* - errorWorker() is an error that occurred on a thread. Therefore, the machine will stop the threads, go back
34+
* to the main thread, and then throw the error.
35+
* - errorDestructor() is an error that occurred on a destructor. Exception on destructors provokes core dumped,
36+
* so we simply output an error message via std::cerr.
37+
*/
38+
2439
// Error managment - How to use:
2540
// error(message, __LINE__, __FUNCTION__, __FILE__);
26-
OP_API void error(const std::string& message, const int line = -1, const std::string& function = "",
27-
const std::string& file = "");
41+
OP_API void error(
42+
const std::string& message, const int line = -1, const std::string& function = "",
43+
const std::string& file = "");
2844

2945
template<typename T>
30-
inline void error(const T& message, const int line = -1, const std::string& function = "",
31-
const std::string& file = "")
46+
inline void error(
47+
const T& message, const int line = -1, const std::string& function = "", const std::string& file = "")
3248
{
3349
error(tToString(message), line, function, file);
3450
}
3551

52+
// Worker error managment
53+
OP_API void checkWorkerErrors();
54+
55+
OP_API void errorWorker(
56+
const std::string& message, const int line = -1, const std::string& function = "",
57+
const std::string& file = "");
58+
59+
template<typename T>
60+
inline void errorWorker(
61+
const T& message, const int line = -1, const std::string& function = "", const std::string& file = "")
62+
{
63+
errorWorker(tToString(message), line, function, file);
64+
}
65+
66+
// Destructor error managment
67+
OP_API void errorDestructor(
68+
const std::string& message, const int line = -1, const std::string& function = "",
69+
const std::string& file = "");
70+
71+
template<typename T>
72+
inline void errorDestructor(
73+
const T& message, const int line = -1, const std::string& function = "", const std::string& file = "")
74+
{
75+
errorDestructor(tToString(message), line, function, file);
76+
}
77+
3678
// Printing info - How to use:
3779
// It will print info if desiredPriority >= sPriorityThreshold
3880
// log(message, desiredPriority, __LINE__, __FUNCTION__, __FILE__);
39-
OP_API void log(const std::string& message, const Priority priority = Priority::Max, const int line = -1,
40-
const std::string& function = "", const std::string& file = "");
81+
OP_API void log(
82+
const std::string& message, const Priority priority = Priority::Max, const int line = -1,
83+
const std::string& function = "", const std::string& file = "");
4184

4285
template<typename T>
43-
inline void log(const T& message, const Priority priority = Priority::Max, const int line = -1,
44-
const std::string& function = "", const std::string& file = "")
86+
inline void log(
87+
const T& message, const Priority priority = Priority::Max, const int line = -1,
88+
const std::string& function = "", const std::string& file = "")
4589
{
4690
log(tToString(message), priority, line, function, file);
4791
}
@@ -50,8 +94,9 @@ namespace op
5094
// It will print info if desiredPriority >= sPriorityThreshold
5195
// dLog(message, desiredPriority, __LINE__, __FUNCTION__, __FILE__);
5296
template<typename T>
53-
inline void dLog(const T& message, const Priority priority = Priority::Max, const int line = -1,
54-
const std::string& function = "", const std::string& file = "")
97+
inline void dLog(
98+
const T& message, const Priority priority = Priority::Max, const int line = -1,
99+
const std::string& function = "", const std::string& file = "")
55100
{
56101
#ifndef NDEBUG
57102
log(message, priority, line, function, file);

0 commit comments

Comments
 (0)