Skip to content

Commit 7768c75

Browse files
committed
tasks queue
1 parent 445659f commit 7768c75

File tree

5 files changed

+124
-3
lines changed

5 files changed

+124
-3
lines changed

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ if(Boost_FOUND)
2424
include_directories(${Boost_INCLUDE_DIRS})
2525
add_executable(cpp_search_qt_creator main.cpp Crowler.h Crowler.cpp root_certificates.hpp
2626
DbManager.h DbManager.cpp
27-
Searcher.h Searcher.cpp)
27+
Searcher.h Searcher.cpp
28+
SafeQueue.h SafeQueue.cpp)
2829
add_subdirectory(./libpqxx-7.9.0 libpqxx-build)
2930
target_compile_features(cpp_search_qt_creator PRIVATE cxx_std_17)
3031
target_link_libraries(cpp_search_qt_creator ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto pqxx)# "${PQXX_LIBRARIES}")

Crowler.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace ssl = net::ssl; // from <boost/asio/ssl.hpp>
2222
using tcp = net::ip::tcp; // from <boost/asio/ip/tcp.hpp>
2323

2424

25-
Crowler::Crowler() {}
25+
2626

2727
void Crowler::processUrl(std::string url, short depth)
2828
{
@@ -151,3 +151,42 @@ void Crowler::savePresencesToDb(std::vector<std::string> words, std::string url)
151151
}
152152

153153
}
154+
155+
Crowler::Crowler()
156+
{
157+
const int cores_count = std::thread::hardware_concurrency(); // количество аппаратных ядер
158+
for (size_t i = 0; i != cores_count; ++i) {
159+
// наполнение вектора, хранящего потоки, задачами на обработку
160+
std::thread t(&Crowler::work, this);
161+
threadsPool_.push_back(std::move(t));
162+
}
163+
}
164+
165+
Crowler::~Crowler()
166+
{
167+
for (auto& thread : threadsPool_) {
168+
// ожидание окончания работы потоков
169+
thread.join();
170+
}
171+
threadsPool_.clear();
172+
}
173+
174+
void Crowler::addToCrowlingQueue(std::string url, unsigned short depth)
175+
{
176+
UrlCrowlingTask task = {url, depth};
177+
tasksQueue_.push(task);
178+
}
179+
180+
void Crowler::work() {
181+
while (true) {
182+
if (!tasksQueue_.isEmpty()) {
183+
// если в очереди задач есть задачи, вынимаем одну и выполняем
184+
UrlCrowlingTask task;
185+
tasksQueue_.pop(task);
186+
processUrl(task.url, task.depth);
187+
} else {
188+
// иначе передаем управление другому потоку
189+
std::this_thread::yield();
190+
}
191+
}
192+
}

Crowler.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,22 @@
33

44
#include <string>
55
#include <regex>
6+
#include <queue>
7+
#include <mutex>
8+
#include <vector>
9+
#include <thread>
610
#include "DbManager.h"
11+
#include "SafeQueue.h""
712
813
class Crowler
914
{
1015
private:
16+
17+
// вектор для хранения потоков обработки задач
18+
std::vector<std::thread> threadsPool_;
19+
// очередь задач на обработку
20+
SafeQueue tasksQueue_;
21+
1122
// скачивание html по url
1223
std::string download(std::string url);
1324
// получение данных из HTML
@@ -18,10 +29,14 @@ class Crowler
1829
std::vector<std::string> getSubUrls(std::string innerHtml);
1930
// вычисление частот слов и сохранение данных в базу
2031
void savePresencesToDb(std::vector<std::string> words, std::string url);
32+
// обход ресурса
33+
void processUrl(std::string url, short depth);
34+
void work();
2135
2236
public:
2337
Crowler();
24-
void processUrl(std::string url, short depth);
38+
~Crowler();
39+
void addToCrowlingQueue(std::string url, unsigned short depth);
2540
};
2641
2742
#endif // CROWLER_H

SafeQueue.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#include "SafeQueue.h"
2+
3+
4+
5+
SafeQueue::SafeQueue() {}
6+
SafeQueue::~SafeQueue() {}
7+
8+
void SafeQueue::push(UrlCrowlingTask task)
9+
{
10+
// добавить новую задачу в очередь
11+
12+
std::lock_guard lock_guard(mutex_);
13+
queue_.push(task);
14+
// уведомление, что очередь не пуста
15+
data_cond.notify_all();
16+
}
17+
18+
void SafeQueue::pop(UrlCrowlingTask &task)
19+
{
20+
// вынуть задачу из очереди
21+
22+
std::unique_lock<std::mutex> lk(mutex_);
23+
// ожидание, что очередь не пуста
24+
data_cond.wait(lk, [this] {return !queue_.empty(); });
25+
task = std::move(queue_.front());
26+
queue_.pop();
27+
}
28+
29+
bool SafeQueue::isEmpty()
30+
{
31+
// проверить, пуста ли очередь
32+
return queue_.empty();
33+
}

SafeQueue.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#ifndef SAFEQUEUE_H
2+
#define SAFEQUEUE_H
3+
4+
#include <queue>
5+
#include <mutex>
6+
7+
struct UrlCrowlingTask {
8+
// Структура, описывающая задачу на обход ресурса
9+
// std::function<void()> func;
10+
std::string url;
11+
unsigned short depth;
12+
};
13+
14+
15+
class SafeQueue
16+
{
17+
public:
18+
SafeQueue();
19+
~SafeQueue();
20+
void push(UrlCrowlingTask task);
21+
void pop(UrlCrowlingTask& task);
22+
bool isEmpty();
23+
24+
private:
25+
// внутренняя очередь для хранения задач
26+
std::queue<UrlCrowlingTask> queue_;
27+
// мьютекс для блокировки на момент добалвения новой задачи в очередь
28+
std::mutex mutex_;
29+
// переменная, используемая для ожидания непустой очереди и уведомления о непустоте
30+
std::condition_variable data_cond;
31+
};
32+
33+
#endif // SAFEQUEUE_H

0 commit comments

Comments
 (0)