[Spec][Ngram] 3/N: Fix synchronization issues in Ngram.cpp (#21186)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
814202704b
commit
59cb9a9da6
@@ -1,10 +1,8 @@
|
|||||||
#include "ngram.h"
|
#include "ngram.h"
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include "trie.h"
|
#include "trie.h"
|
||||||
|
|
||||||
@@ -72,12 +70,10 @@ Ngram::Ngram(size_t capacity, const Param& param) : param_(param) {
|
|||||||
|
|
||||||
trie_ = std::make_unique<Trie>(capacity, param_);
|
trie_ = std::make_unique<Trie>(capacity, param_);
|
||||||
|
|
||||||
quit_flag_ = false;
|
|
||||||
insert_worker_ = std::thread(&Ngram::insertWorker, this);
|
insert_worker_ = std::thread(&Ngram::insertWorker, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ngram::~Ngram() {
|
Ngram::~Ngram() {
|
||||||
quit_flag_ = true;
|
|
||||||
insert_queue_.close();
|
insert_queue_.close();
|
||||||
if (insert_worker_.joinable()) {
|
if (insert_worker_.joinable()) {
|
||||||
insert_worker_.join();
|
insert_worker_.join();
|
||||||
@@ -85,25 +81,31 @@ Ngram::~Ngram() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Ngram::synchronize() const {
|
void Ngram::synchronize() const {
|
||||||
while (!insert_queue_.empty()) {
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(10));
|
sync_cv_.wait(lock, [this] { return pending_count_ == 0; });
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ngram::asyncInsert(std::vector<std::vector<int32_t>>&& tokens) {
|
void Ngram::asyncInsert(std::vector<std::vector<int32_t>>&& tokens) {
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
pending_count_ += tokens.size();
|
||||||
|
}
|
||||||
for (auto&& token : tokens) {
|
for (auto&& token : tokens) {
|
||||||
insert_queue_.enqueue(std::move(token));
|
insert_queue_.enqueue(std::move(token));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ngram::insertWorker() {
|
void Ngram::insertWorker() {
|
||||||
while (!quit_flag_) {
|
for (;;) {
|
||||||
std::vector<int32_t> data;
|
std::vector<int32_t> data;
|
||||||
if (!insert_queue_.dequeue(data)) {
|
if (!insert_queue_.dequeue(data)) {
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
std::unique_lock<std::mutex> lock(mutex_);
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
trie_->insert(data.data(), data.size());
|
trie_->insert(data.data(), data.size());
|
||||||
|
--pending_count_;
|
||||||
|
lock.unlock();
|
||||||
|
sync_cv_.notify_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -18,8 +19,14 @@ class Ngram {
|
|||||||
std::unique_ptr<Trie> trie_;
|
std::unique_ptr<Trie> trie_;
|
||||||
Param param_;
|
Param param_;
|
||||||
|
|
||||||
|
// NOTE: protects trie_ and pending_count_. Ensures batchMatch never reads
|
||||||
|
// trie_ while insertWorker is writing. After synchronize(), no pending
|
||||||
|
// inserts remain so mutex_ contention is effectively zero.
|
||||||
mutable std::mutex mutex_;
|
mutable std::mutex mutex_;
|
||||||
bool quit_flag_ = false;
|
mutable std::condition_variable sync_cv_;
|
||||||
|
// NOTE: tracks inserts from enqueue through trie_->insert() completion,
|
||||||
|
// not just queue occupancy. A dequeued item may still be mid-insert.
|
||||||
|
size_t pending_count_ = 0;
|
||||||
utils::Queue<std::vector<int32_t>> insert_queue_;
|
utils::Queue<std::vector<int32_t>> insert_queue_;
|
||||||
std::thread insert_worker_;
|
std::thread insert_worker_;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user