260 lines
6.5 KiB
C++
260 lines
6.5 KiB
C++
// Copyright 2025-present the zvec project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include <iostream>
|
|
#include <memory>
|
|
#include <vector>
|
|
#include <zvec/ailego/parallel/thread_pool.h>
|
|
|
|
#define private public
|
|
#include <ailego/parallel/multi_thread_list.h>
|
|
#undef private
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
using namespace zvec;
|
|
using namespace zvec::ailego;
|
|
using namespace std;
|
|
|
|
struct Item {
|
|
uint32_t a_;
|
|
std::string b_;
|
|
Item() {};
|
|
Item(uint32_t a, std::string b) : a_(a), b_(b) {}
|
|
};
|
|
|
|
MultiThreadList<Item> mt_queue(100);
|
|
|
|
void producer(uint32_t i) {
|
|
Item item{i, std::to_string(i)};
|
|
mt_queue.produce(item);
|
|
return;
|
|
}
|
|
void consumer(uint32_t i, uint32_t *result) {
|
|
Item item;
|
|
while (mt_queue.consume(&item)) {
|
|
*result += item.a_;
|
|
}
|
|
}
|
|
void producer_done(uint32_t i) {
|
|
Item item{i, std::to_string(i)};
|
|
EXPECT_EQ(false, mt_queue.produce(item));
|
|
return;
|
|
}
|
|
|
|
TEST(MultiThreadListTest, General) {
|
|
int times = 100;
|
|
while (times--) {
|
|
cout << "================================" << endl;
|
|
cout << "times: " << times << endl;
|
|
|
|
mt_queue.reset();
|
|
|
|
ailego::ThreadPool producer_pool;
|
|
ailego::ThreadPool consumer_pool;
|
|
ailego::ThreadPool producer_done_pool;
|
|
|
|
uint32_t num_of_consumer = 100;
|
|
uint32_t num_of_producer = 100;
|
|
uint32_t num_of_producer_done = 100;
|
|
|
|
std::vector<uint32_t> consumer_results(num_of_consumer, 0);
|
|
|
|
for (uint32_t i = 0; i < num_of_consumer; i++) {
|
|
consumer_pool.execute(consumer, i + 1, &consumer_results[i]);
|
|
}
|
|
|
|
for (uint32_t i = 0; i < num_of_producer; i++) {
|
|
producer_pool.execute(producer, i + 1);
|
|
}
|
|
|
|
producer_pool.wait_finish();
|
|
mt_queue.done();
|
|
consumer_pool.wait_finish();
|
|
|
|
// produce after queue done
|
|
for (uint32_t i = 0; i < num_of_producer_done; i++) {
|
|
producer_done_pool.execute(producer_done, i + 1);
|
|
}
|
|
producer_done_pool.wait_finish();
|
|
|
|
uint32_t total = 0;
|
|
for (uint32_t i = 0; i < num_of_consumer; i++) {
|
|
cout << consumer_results[i] << " ";
|
|
total += consumer_results[i];
|
|
}
|
|
cout << endl;
|
|
|
|
EXPECT_EQ(total, 5050);
|
|
}
|
|
}
|
|
|
|
TEST(MultiThreadListTest, FullQueueQuit) {
|
|
mt_queue.reset();
|
|
|
|
ailego::ThreadPool producer_pool;
|
|
|
|
uint32_t num_of_producer = 1000;
|
|
|
|
for (uint32_t i = 1; i <= num_of_producer; i++) {
|
|
producer_pool.execute(producer, i);
|
|
}
|
|
|
|
mt_queue.done();
|
|
producer_pool.wait_finish();
|
|
}
|
|
|
|
TEST(MultiThreadListTest, ConsumeStopResume) {
|
|
mt_queue.reset();
|
|
|
|
ailego::ThreadPool producer_pool;
|
|
ailego::ThreadPool consumer_pool;
|
|
|
|
constexpr uint32_t num_of_consumer = 100;
|
|
constexpr uint32_t num_of_producer = 100;
|
|
|
|
std::vector<uint32_t> consumer_results(2 * num_of_consumer);
|
|
std::fill(consumer_results.begin(), consumer_results.end(), 0);
|
|
|
|
for (uint32_t i = 0; i < num_of_consumer; i++) {
|
|
consumer_pool.execute(consumer, i + 1, &consumer_results[i]);
|
|
}
|
|
|
|
for (uint32_t i = 0; i < num_of_producer; i++) {
|
|
producer_pool.execute(producer, i + 1);
|
|
}
|
|
|
|
producer_pool.wait_finish();
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
|
mt_queue.stop_consume();
|
|
consumer_pool.wait_finish();
|
|
|
|
uint32_t total = 0;
|
|
for (uint32_t i = 0; i < num_of_consumer; i++) {
|
|
cout << consumer_results[i] << " ";
|
|
total += consumer_results[i];
|
|
}
|
|
cout << endl;
|
|
|
|
cout << "mt queue size: " << mt_queue.list_.size() << endl;
|
|
|
|
EXPECT_EQ(total, 5050);
|
|
|
|
for (uint32_t i = num_of_producer; i < 2 * num_of_producer; i++) {
|
|
producer_pool.execute(producer, i + 1);
|
|
}
|
|
|
|
mt_queue.resume_consume();
|
|
|
|
for (uint32_t i = num_of_producer; i < 2 * num_of_consumer; i++) {
|
|
consumer_pool.execute(consumer, i + 1, &consumer_results[i]);
|
|
}
|
|
|
|
producer_pool.wait_finish();
|
|
mt_queue.done();
|
|
consumer_pool.wait_finish();
|
|
|
|
total = 0;
|
|
for (uint32_t i = num_of_consumer; i < 2 * num_of_consumer; i++) {
|
|
cout << consumer_results[i] << " ";
|
|
total += consumer_results[i];
|
|
}
|
|
cout << endl;
|
|
|
|
cout << "mt queue size: " << mt_queue.list_.size() << endl;
|
|
|
|
EXPECT_EQ(total, 15050);
|
|
}
|
|
|
|
struct MoveableItem {
|
|
uint32_t a_;
|
|
std::string b_;
|
|
MoveableItem() {};
|
|
MoveableItem(uint32_t a, std::string b) : a_(a), b_(b) {}
|
|
|
|
MoveableItem(const MoveableItem &) = delete;
|
|
MoveableItem &operator=(const MoveableItem &) = delete;
|
|
|
|
MoveableItem(MoveableItem &&) = default;
|
|
MoveableItem &operator=(MoveableItem &&) = default;
|
|
};
|
|
|
|
MultiThreadList<MoveableItem> mt_moveable_queue(100);
|
|
|
|
void producer_moveable(uint32_t i) {
|
|
MoveableItem item{i, std::to_string(i)};
|
|
mt_moveable_queue.produce(std::move(item));
|
|
return;
|
|
}
|
|
void consumer_moveable(uint32_t i, uint32_t *result) {
|
|
MoveableItem item;
|
|
while (mt_moveable_queue.consume(&item)) {
|
|
*result += item.a_;
|
|
}
|
|
}
|
|
void producer_moveable_done(uint32_t i) {
|
|
MoveableItem item{i, std::to_string(i)};
|
|
EXPECT_EQ(false, mt_moveable_queue.produce(std::move(item)));
|
|
return;
|
|
}
|
|
|
|
TEST(MultiThreadListTest, General_Moveable) {
|
|
int times = 100;
|
|
while (times--) {
|
|
cout << "================================" << endl;
|
|
cout << "times: " << times << endl;
|
|
|
|
mt_moveable_queue.reset();
|
|
|
|
ailego::ThreadPool producer_pool;
|
|
ailego::ThreadPool consumer_pool;
|
|
ailego::ThreadPool producer_done_pool;
|
|
|
|
uint32_t num_of_consumer = 100;
|
|
uint32_t num_of_producer = 100;
|
|
uint32_t num_of_producer_done = 100;
|
|
|
|
std::vector<uint32_t> consumer_results(num_of_consumer, 0);
|
|
|
|
for (uint32_t i = 0; i < num_of_consumer; i++) {
|
|
consumer_pool.execute(consumer_moveable, i + 1, &consumer_results[i]);
|
|
}
|
|
|
|
for (uint32_t i = 0; i < num_of_producer; i++) {
|
|
producer_pool.execute(producer_moveable, i + 1);
|
|
}
|
|
|
|
producer_pool.wait_finish();
|
|
mt_moveable_queue.done();
|
|
consumer_pool.wait_finish();
|
|
|
|
// produce after queue done
|
|
for (uint32_t i = 0; i < num_of_producer_done; i++) {
|
|
producer_done_pool.execute(producer_moveable_done, i + 1);
|
|
}
|
|
producer_done_pool.wait_finish();
|
|
|
|
uint32_t total = 0;
|
|
for (uint32_t i = 0; i < num_of_consumer; i++) {
|
|
cout << consumer_results[i] << " ";
|
|
total += consumer_results[i];
|
|
}
|
|
cout << endl;
|
|
|
|
EXPECT_EQ(total, 5050);
|
|
}
|
|
}
|