Bonjour,
Je travaille sur un projet (un jeu) et en testant la classe chargé de gérer la répartition des taches sur plusieurs thread je suis arrivé à une erreur incompréhensible, celle ci ce produit car un thread (Thread 2) accède a la file de tache pendant que le thread 1 la check, le problème étant que ces codes sont censé être dans des mutex ... Donc ca devrait pas ce produire ...
En désactiver les thread secondaires, il n'y a pas d'erreur à l’exécution.
N'ayant aucune réponse sur le site du zéro, je tente ce forum (pourquoi pas dirait on).
Le code : (Le lien du plantage est dans TaskManager.cpp et est indiqué en commentaire)
TaskManager.hpp:
- pragma once
- include <functional>
- include <vector>
- include <mutex>
- include <thread>
- include <deque>
- include "Semaphore.hpp"
class TaskManager
{
public:
TaskManager ();
~TaskManager ();
void pollCallback (unsigned int taskTimeLimit);
void setThreadNumber (unsigned int number); /// <<< 2
inline void addCallback (const std::function <void (void)>& callback)
{
m_mutex.lock ();
m_callbackQueue.push_back (callback);
m_mutex.unlock ();
}
inline void addTask (const std::function <void (void)>& task)
{
m_mutex.lock ();
m_taskQueue.push_back (task);
m_semaphore.post ();
m_mutex.unlock ();
}
private:
std::deque <std::function <void (void)>> m_callbackQueue;
std::deque <std::function <void (void)> > m_taskQueue;
std::mutex m_mutex;
struct ThreadData
{
std::thread* thread;
bool quit;
};
std::vector <ThreadData> m_threadPool;
Semaphore m_semaphore;
};
TaskManager.cpp:
- include "TaskManager.hpp"
- include <exception>
- include <ctime>
TaskManager::TaskManager ()
{
}
TaskManager::~TaskManager ()
{
setThreadNumber (1);
}
void TaskManager::pollCallback (unsigned int taskTimeLimit)
{
clock_t c = clock ();
m_mutex.lock ();
while (true)
{
while (!m_callbackQueue.empty ()) // <<< Sa plante toujours ici
{
std::function <void (void)> f = m_callbackQueue.front ();
m_callbackQueue.pop_front ();
m_mutex.unlock ();
f ();
m_mutex.lock ();
}
if (m_taskQueue.empty () || (unsigned int) (clock () - c) / (CLOCKS_PER_SEC / 1000) > taskTimeLimit)
break;
if (m_semaphore.trywait ())
{
std::function <void (void)> f = m_taskQueue.front ();
m_taskQueue.pop_front ();
m_mutex.unlock ();
f ();
m_mutex.lock ();
}
}
m_mutex.unlock ();
}
void TaskManager::setThreadNumber (unsigned int number)
{
- ifdef _DEBUG
if (number == 0)
{
throw std::invalid_argument ("Can not set the program to have 0 threads");
}
- endif
number --;
if (number == m_threadPool.size ())
return;
else if (number > m_threadPool.size ())
{
const unsigned int last = m_threadPool.size ();
m_threadPool.resize (number);
for (unsigned int i = last ; i < number ; i++)
{
ThreadData& current = m_threadPool [i];
current.quit = false;
current.thread = new std::thread ([this, ¤t] ()
{
while (!current.quit)
{
m_mutex.lock ();
while (m_semaphore.trywait ())
{
std::function <void (void)> f = m_taskQueue.front ();
m_taskQueue.pop_front ();
m_mutex.unlock ();
f ();
m_mutex.lock ();
}
m_mutex.unlock ();
std::unique_lock <std::mutex> lock (m_mutex);
m_semaphore.wait (lock);
}
});
}
}
else
{
for (unsigned int i = number ; i < m_threadPool.size () ; i++)
{
ThreadData& current = m_threadPool [i];
current.quit = true;
delete current.thread;
}
m_threadPool.resize (number);
}
}
Semaphore.hpp:
- pragma once
- include <condition_variable>
- include <mutex>
class Semaphore
{
public:
Semaphore ()
{
}
~Semaphore ()
{
m_cond.notify_all ();
}
inline void post ()
{
m_counter++;
m_cond.notify_one ();
}
inline void wait (std::unique_lock <std::mutex>& lock)
{
while (!m_counter)
m_cond.wait (lock);
m_counter --;
return;
}
inline bool trywait ()
{
bool ok = m_counter != 0;
if (ok)
m_counter --;
return ok;
}
private:
unsigned int m_counter;
std::condition_variable m_cond;
};
Merci d'avance