Я пытаюсь запустить многопоточную очередь заданий на С ++. В качестве примера я протестировал следующую программу:
#include <thread>
#include <mutex>
#include <list>
#include <vector>
class Job
{
public:
void Run(void)
{
}
};
class Queue
{
private:
std::recursive_mutex mtxJobs;
std::list<Job *> mJobs;
public:
Job *Take(void)
{
std::scoped_lock(mtxJobs);
if (mJobs.size() > 0)
{
Job *pJob(mJobs.front());
mJobs.pop_front();
return pJob;
}
else
return NULL;
}
void Add(Job *pJob)
{
std::scoped_lock(mtxJobs);
mJobs.push_back(pJob);
}
size_t Size(void)
{
std::scoped_lock(mtxJobs);
return mJobs.size();
}
};
void Work(Queue &q)
{
Job *pJob;
while ((pJob = q.Take()) != NULL)
{
pJob->Run();
delete pJob;
}
}
int main()
{
size_t i;
Queue q;
for (i = 0; i < 1000; i++)
q.Add(new Job);
std::vector<std::thread> threads(4);
for (i = 0; i < 4; i++)
threads[i] = std::thread(Work, std::ref(q));
for (i = 0; i < 4; i++)
threads[i].join();
return 0;
}
Когда я запускаю это так:
g++ -std=c++17 -lpthread test.cpp -o test && ./test
он вылетает с ошибкой SEGFAULT. Кто-нибудь знает, почему?
GDB указывает, что сбой всегда происходит при доступе к списку mJobs. Однако блокировки должны предотвращать одновременное изменение, верно?
Может кто-нибудь мне помочь?





Вы обращаетесь к своей очереди без синхронизации:
std::scoped_lock(mtxJobs);
это локальная переменная с именем mtxJobs, которая создается без аргументов и скрывает ваш член мьютекса mtxJobs. Когда scoped_lock создается без аргументов, он ничего не делает в соответствии с ссылка.
Вам нужно написать:
std::scoped_lock lock(mtxJobs);
теперь ваш мьютекс заблокирован в ctor объекта scoped_lock.
Ага. Поэтому лучше использовать lock_guard.
Как я мог это пропустить! Я изменил это, как вы сказали, и теперь у меня больше нет вылетов. Спасибо!
Примечание + Вместо
newing иdeleteingJobрассмотрите возможность передачиstd::unique_ptr<Job>. в нем явно указывается право собственности наJobи в значительной степени гарантируется его выпуск, если в процессе что-то пойдет не так.