Reputation: 11
I wrote a thread pool by myself, and the Result class is used to obtain the calculation results of the thread pool tasks. Initially, I used a simple semaphore mechanism to implement thread synchronization. The code is as follows:
void Semaphore::wait() {
std::unique_lock<std::mutex> lock(mutex_);
condition_.wait(lock, [&] { return count_ > 0; });
--count_;
}
void Semaphore::signal() {
std::unique_lock<std::mutex> lock(mutex_);
++count_;
condition_.notify_all();
}
Any Result::get() {
if (!isValid_)
return "";
sem_.wait();
return std::move(any_);
}
void Result::setAny(Any any) {
this->any_ = std::move(any);
sem_.signal();
}
The get() method is used to obtain the calculation result of the task in the thread pool. If the calculation is not completed, get() will be blocked. setAny is called in the thread pool to store the calculation result of the task.
Later, I thought about whether I could use locks and condition_variables to achieve synchronization directly, and then I abandoned the Semaphore class and used locks and condition variables directly in get() and setAny(), but I found that the thread would be blocked when get() was called at the end. Why is this?
By the way, if there is only one thread in the thread pool, the program can be executed smoothly; but if there is more than one thread and the number of tasks is greater than one, the above problems will occur.The code is as follows:
Any Result::get() {
if (!isValid_)
return "";
std::unique_lock<std::mutex> lock(mtx);
cd.wait(lock);
return std::move(any_);
}
void Result::setAny(Any any) {
this->any_ = std::move(any);
cd.notify_one();
}
Here is the complete code for this part:
class Semaphore {
private:
std::mutex mutex_;
std::condition_variable condition_;
std::atomic_int count_;
public:
explicit Semaphore(int count = 0) : count_(count) {
};
~Semaphore() = default;
Semaphore(const Semaphore &) = delete;
Semaphore &operator=(const Semaphore &) = delete;
Semaphore(Semaphore &&) = delete;
Semaphore &operator=(Semaphore &&) = delete;
void wait();
void signal();
};
class Result {
private:
Any any_;
std::shared_ptr<Task> task_;
bool isValid_;
// Semaphore sem_;
std::mutex mtx;
std::condition_variable cd;
public:
explicit Result(std::shared_ptr<Task> task, bool isValid = true);
Result(Result &&) = default;
~Result() = default;
Any get();
void setAny(Any);
};
The above is the complete code. At first, I used "Semaphore sem_;" to simulate a simple semaphore mechanism, but later I felt that the count_ variable in Semaphore was not very important, and similar functions could be achieved using only mutex and condition_variable, which led to the above problem.
Upvotes: 0
Views: 101