如何使线程池任务成为抽象函数类型



我正在尝试实现非常简单的C++线程池。到目前为止,我已经检查过了。然而,我想把任务做成抽象的形式。我搜索了几十篇文章,它们似乎不是我想要的。(也许我的关键词不合适…(目前,只有

void (*)()

表单可以作为任务函数接受。下面写着简单的代码。

#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <Windows.h>
class CYSThreadPool
{
private:
static std::thread** s_ppThreads;
static long s_lThreadCount;
static bool s_bJoin;
static std::mutex* s_pMutexJoin;
static std::queue<void (*)()> s_queueTasks;
static std::mutex* s_pMutexTasks;
CYSThreadPool(){}
~CYSThreadPool(){}
static void ThreadFunction()
{
while (true)
{
if (!s_pMutexJoin->try_lock())
continue;
bool bJoin = s_bJoin;
s_pMutexJoin->unlock();
if (bJoin)
break;
if (!s_pMutexTasks->try_lock())
continue;
void (*fp)() = nullptr;
if (s_queueTasks.size() > 0ull)
{
fp = s_queueTasks.front();
s_queueTasks.pop();
}
s_pMutexTasks->unlock();
if (fp != nullptr)
fp();
}
}
public:
enum class EResult : unsigned long
{
Success = 0ul,
Fail_Undefined = 1ul,
Fail_InvalidThreadCount = 2ul,
Fail_ArgumentNull = 3ul
};
static const EResult Join()
{
if (s_ppThreads == nullptr)
{
if (s_lThreadCount == 0l)
return EResult::Success;
else
return EResult::Fail_Undefined;
}
else
{
if (s_lThreadCount <= 0l)
return EResult::Fail_Undefined;
else
{
s_pMutexJoin->lock();
s_bJoin = true;
s_pMutexJoin->unlock();
for (long i = 0l; i < s_lThreadCount; ++i)
{
s_ppThreads[i]->join();
s_ppThreads[i] = nullptr;
}
delete s_ppThreads;
s_ppThreads = nullptr;
s_lThreadCount = 0l;
s_pMutexJoin->lock();
s_bJoin = false;
s_pMutexJoin->unlock();
}
}
return EResult::Success;
}
static const EResult CreateThreads(const long _lThreadCount)
{
if (_lThreadCount < 0l)
return EResult::Fail_InvalidThreadCount;
if (Join() != EResult::Success)
return EResult::Fail_Undefined;
if (_lThreadCount == 0l)
return EResult::Success;
s_ppThreads = new std::thread*[_lThreadCount]{};
for (long i = 0l; i < _lThreadCount; ++i)
s_ppThreads[i] = new std::thread(ThreadFunction);
s_lThreadCount = _lThreadCount;
return EResult::Success;
}
static const EResult AddTask(void (*_fp)())
{
if (_fp == nullptr)
return EResult::Fail_ArgumentNull;
s_pMutexTasks->lock();
s_queueTasks.push(_fp);
s_pMutexTasks->unlock();
return EResult::Success;
}
};
std::thread** CYSThreadPool::s_ppThreads = nullptr;
long CYSThreadPool::s_lThreadCount = 0l;
bool CYSThreadPool::s_bJoin = false;
std::mutex* CYSThreadPool::s_pMutexJoin = new std::mutex();
std::queue<void (*)()> CYSThreadPool::s_queueTasks;
std::mutex* CYSThreadPool::s_pMutexTasks = new std::mutex();
void Test0()
{
for (long i = 0l; i < 100000l; ++i)
{
std::cout << "A";
}
}
int main()
{
CYSThreadPool::EResult eResult = CYSThreadPool::Join();
eResult = CYSThreadPool::CreateThreads(-1l);
eResult = CYSThreadPool::CreateThreads(1l);
eResult = CYSThreadPool::CreateThreads(0l);
eResult = CYSThreadPool::CreateThreads(2l);
CYSThreadPool::AddTask(Test0);
Sleep(1000ul);
CYSThreadPool::Join();
return 0;
}

我们将衷心感谢您的回答!

编辑:

我所说的"抽象形式的函数"是指获得void((((以外的任何函数类型。例如void(((long(、void((、(ID3D12Resource1、IDXGISwapChain(或HResult(ID3D12Device6,ID3D12Resource 1*、IDXGIS-wapChaine(等等

感谢您对使用condition_variable代替try_lock并将fp((包装到try-catch中的评论。对不起,我不明白你的意思。我可以询问更多细节吗?

因此,这里有一些东西可以改进您的代码:

  1. 您可以使用std::function<void((>而不是void(*)()。这将允许您调用任何可调用的指针,而不仅仅是函数指针,方法是将它们封装在lambda中,例如CYSThreadPool::AddTask([]() { Add(3, 1); });
  2. 更好的是,制作一个抽象基类,比如使用虚拟.Run()方法的Task,然后使用它。如果需要,可以从中派生FunctionPointerTaskStdFunctionTask(显然可以更改名称(。您可以创建例如ProcessResource1Task,并将必要的参数传递给构造函数,以便.Run()只执行它
  3. 你的ThreadFunction员工效率很低。你一直在try_lock上旋转。不要。请改用condition_variables
  4. 更好的是,将排队的东西移动到一个单独的线程安全队列类中
  5. 您的代码不是异常安全的。不要使用手动锁定/try_lock,而是使用lock_guard或unique_lock。事实上,您的代码很容易死锁。如果必须使用手动锁定/try_lock,则必须使用try-catch
  6. 有很多静态变量。不要。使它们都成为非静态成员,添加适当的构造函数和析构函数。一旦加入,您的线程池将完全不可用。Plus Join((不是线程安全的(如果线程池不是完全静态的,那就没那么重要了(
  7. 您可以通过使bool s_bJoin原子化来提高性能。没有必要在锁下读/写它

可能还有一些其他问题,这就是我现在所能看到的。

您还可以查看此代码以获得不错的线程池实现。它很简短,并利用了上述大部分提示。

最新更新