@@ -23,7 +23,7 @@ class TaskQueue {
23
23
24
24
static void pushTask ( VoidFunc f )
25
25
{
26
- // TODO: later, use a single thread and queue the tasks
26
+ // TODO: later, optionally use a single thread and queue the tasks
27
27
// e.g. http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html
28
28
// for now, a thread per task will help spec out the right interface:
29
29
std::thread taskThread ( &TaskQueue::doWork, f );
@@ -67,7 +67,7 @@ class UiTaskQueue {
67
67
return mCompletedTasks > taskId;
68
68
}
69
69
70
- // only call from main thread, no canceling from background threads mmmkay?
70
+ // only call from main thread, no canceling from background threads yet :(
71
71
static void cancelTask ( uint64_t taskId )
72
72
{
73
73
if (!isTaskComplete (taskId)) {
@@ -76,44 +76,58 @@ class UiTaskQueue {
76
76
}
77
77
78
78
// call this from the UI thread, or pain will occur
79
- static void popTask ( )
79
+ // default ~5ms budget (but will always do at least one call)
80
+ static void update ( const float &budgetSeconds = 0 .005f )
80
81
{
81
- float t = ci::app::getElapsedSeconds ();
82
- do {
83
- // TODO: within a certain time limit, keep popping tasks
84
- if (mFunctionsMutex .try_lock ()) {
85
- if (mFunctions .empty ()) {
86
- mFunctionsMutex .unlock ();
87
- break ; // quit the do/while
82
+ // empty while loop *shiver*
83
+ const float t = ci::app::getElapsedSeconds ();
84
+ while ( popTask () && ci::app::getElapsedSeconds () - t < budgetSeconds );
85
+ }
86
+
87
+ private:
88
+
89
+ // returns true if it got a lock and has more tasks, false otherwise
90
+ static bool popTask ( )
91
+ {
92
+ if (mFunctionsMutex .try_lock ()) {
93
+ if (mFunctions .empty ()) {
94
+ mFunctionsMutex .unlock ();
95
+ return false ;
96
+ }
97
+ else {
98
+ // remember this id and increment too;
99
+ // (it's about to be gone from mFunctions so cancelTask won't work anyway)
100
+ uint64_t thisTaskId = mCompletedTasks ++;
101
+
102
+ // grab the next task and remove it; there is no undo
103
+ VoidFunc f = mFunctions .front ();
104
+ mFunctions .pop ();
105
+
106
+ // let callers know if it's worth calling again
107
+ bool hasMoreTasks = !mFunctions .empty ();
108
+
109
+ // unlock first so that tasks can queue other tasks
110
+ mFunctionsMutex .unlock ();
111
+
112
+ // if it's not canceled, do it (otherwise just clean up the canceled marker)
113
+ std::set<uint64_t >::iterator iter = mCanceledIds .find ( thisTaskId );
114
+ if ( iter == mCanceledIds .end () ) {
115
+ f ();
88
116
}
89
117
else {
90
- uint64_t thisTaskId = mCompletedTasks ++; // remember this id and increment too;
91
- // (it's about to be gone from mFunctions so cancelTask won't work anyway)
92
- VoidFunc f = mFunctions .front (); // grab the next task
93
- mFunctions .pop (); // remove it; there is no undo
94
- mFunctionsMutex .unlock (); // unlock first so that tasks can queue other tasks
95
- std::set<uint64_t >::iterator iter = mCanceledIds .find ( thisTaskId );
96
- if ( iter == mCanceledIds .end () ) {
97
- // if it's not canceled, do it
98
- std::cout << " performing task " << thisTaskId << std::endl;
99
- f ();
100
- }
101
- else {
102
- std::cout << " skipping task " << thisTaskId << std::endl;
103
- // otherwise remove it
104
- mCanceledIds .erase ( iter );
105
- }
118
+ mCanceledIds .erase ( iter );
106
119
}
120
+
121
+ return hasMoreTasks;
107
122
}
108
- } while ( ci::app::getElapsedSeconds () - t < 0.005 ); // ~5ms budget (but always do at least one call)
123
+ }
124
+ return false ;
109
125
}
110
126
111
- private:
112
-
113
127
static std::mutex mFunctionsMutex ;
114
128
static std::queue<VoidFunc> mFunctions ;
115
129
static uint64_t mCompletedTasks ;
116
130
static uint64_t mTotalTasks ;
117
- static std::set<uint64_t > mCanceledIds ;
131
+ static std::set<uint64_t > mCanceledIds ; // FIXME: no mutex for canceling so not thread safe :(
118
132
119
133
};
0 commit comments