void AsyncThreadManager::itemConsumer(WorkQueue& workQueue, condition_variable& workAvailable, recursive_mutex& queueMutex, bool &finished) { while(true) { cz::unique_lock<cz::recursive_mutex> queueLock(queueMutex); while(!finished && workQueue.empty()) workAvailable.wait(queueLock); if (finished) break; detail::AsyncWorkItemBase* workItem = workQueue.front(); workQueue.pop(); // unlock so other threads can remove work items while we compute this one queueLock.unlock(); // Compute the result (this will put the value in the "future" object the user is holding) workItem->run(); CZ_DELETE workItem; } }
// generalized equivalence processing (left and right) // basically, goes through every vertex in a class and checks if all successor or // predecessor classes match in all vertices. if classes mismatch, a vertex is // split into a separate class, along with all vertices having the same set of // successor/predecessor classes. the opposite side (successors for left // equivalence, predecessors for right equivalence) classes get revalidated in // case of a split. static void equivalence(vector<VertexInfoSet> &classes, WorkQueue &work_queue, EquivalenceType eq_type) { // now, go through the work queue until it's empty map<flat_set<unsigned>, VertexInfoSet> tentative_classmap; flat_set<unsigned> cur_classes; // local work queue, to store classes we want to revalidate in case of split WorkQueue reval_queue(work_queue.capacity()); while (!work_queue.empty()) { // dequeue our class from the work queue unsigned cur_class = work_queue.pop(); // get all vertices in current equivalence class VertexInfoSet &cur_class_vertices = classes.at(cur_class); if (cur_class_vertices.size() < 2) { continue; } // clear data from previous iterations tentative_classmap.clear(); DEBUG_PRINTF("doing equivalence pass for class %u, %zd vertices\n", cur_class, cur_class_vertices.size()); // go through vertices in this class for (VertexInfo *vi : cur_class_vertices) { cur_classes.clear(); // get vertex lists for equivalence vertices and vertices for // revalidation in case of split const auto &eq_vertices = (eq_type == LEFT_EQUIVALENCE) ? vi->pred : vi->succ; const auto &reval_vertices = (eq_type == LEFT_EQUIVALENCE) ? vi->succ : vi->pred; // go through equivalence and note the classes for (const VertexInfo *tmp : eq_vertices) { cur_classes.insert(tmp->equivalence_class); } // note all the classes that need to be reevaluated for (const VertexInfo *tmp : reval_vertices) { reval_queue.push(tmp->equivalence_class); } VertexInfoSet &tentative_classes = tentative_classmap[cur_classes]; tentative_classes.insert(vi); } // if we found more than one class, split and revalidate everything if (tentative_classmap.size() > 1) { auto tmi = tentative_classmap.begin(); // start from the second class for (++tmi; tmi != tentative_classmap.end(); ++tmi) { const VertexInfoSet &vertices_to_split = tmi->second; unsigned new_class = classes.size(); VertexInfoSet new_class_vertices; for (VertexInfo *vi : vertices_to_split) { vi->equivalence_class = new_class; // note: we cannot use the cur_class_vertices ref, as it is // invalidated by modifications to the classes vector. classes[cur_class].erase(vi); new_class_vertices.insert(vi); } classes.push_back(move(new_class_vertices)); if (contains(tmi->first, cur_class)) { reval_queue.push(new_class); } } work_queue.append(reval_queue); } reval_queue.clear(); } }