c ++提升多线程,如何排队线程

时间:2014-03-06 21:10:51

标签: c++ multithreading boost

我正在构建自己的网络服务器,我希望它是多线程的。我不知道如何启动新线程,将其存储在某个列表中,检测线程何时完成并从等待队列添加一些新线程。谁能给我一个简单的例子如何做到这一点?现在我以这种方式运行线程:

boost::thread t(app, client_fd); // but it's not good way because I can't control it

下面是pseucode,它说明了我的意思:

class worker
{
    public:
    void run(int cfd)
    {
    // do something
    }
}

std::vector<int> waitQueue;
std::vector<worker> runningQueue;

onAcceptClient(int client_fd)
{
    waitQueue.insert(client_fd);
}

while(1) // this must run in single thread
{
    client_fd = accept(...);
    onAcceptClient(client_fd);
}

while(1) // this must run in single thread
{
    if (runningQueue.size() < 128)
    {
       int diff = 128 - runningQueue.size() ;
       for (int a = 0; a < diff; a++)
       {
        int cfc = waitQueue.pop();
        worker w;
        w.run(cfc);
        runningQueue.insert(w);
       }
     }
}

2 个答案:

答案 0 :(得分:0)

这是我实现这个的方法。

首先,我有一个基本的ThreadWorker类,我的实际处理任务可以来自。请注意,这是特定于Windows的,但您可以将boost mutex替换为CriticalSection,并且信号量的POSIX实现位于:http://linux.die.net/man/7/sem_overview

class ThreadWorker
{
public:
ThreadWorker(void)
{
    signalfinished = NULL;
    forcesignal = false;
}
virtual ~ThreadWorker(void)
{
    if (signalfinished!=NULL)   ReleaseSemaphore(signalfinished,1,NULL);
}

DWORD ThreadId;
HANDLE threadhandle;
HANDLE signalfinished;
bool forcesignal;

static DWORD WINAPI workerthread(void *param)
{
    ThreadWorker *worker = (ThreadWorker*)param;
    worker->signalfinished = CreateSemaphore(NULL,0,1,NULL);
    worker->RunTask();
    ReleaseSemaphore(worker->signalfinished,1,NULL);
}

void StartWorker()
{
    CreateThread(NULL,NULL,ThreadWorker::workerthread,this,0,&ThreadId);
}

void WaitUntilWorkerFinished()
{
    DWORD waitresult;
    do
    {
        waitresult = WaitForSingleObject(signalfinished,1000);
    } while (waitresult!=WAIT_OBJECT_0 && !forcesignal);

}
virtual void RunTask()=0;
};

然后,我有一个ThreadManager来管理ThreadWorker对象的队列。同样,您可以将互斥锁替换为CriticalSection。我更喜欢std :: list到std :: vector,因为vector是连续的。

    class ThreadManager
{
    CRITICAL_SECTION critsec;
    std::list<ThreadWorker*> taskqueue;
public:
    ThreadManager(void)
    {
        InitializeCriticalSection(&critsec);
    }
    void AddTaskToQueue(ThreadWorker *task)
    {
        EnterCriticalSection(&critsec);
        taskqueue.push_back(task);
        LeaveCriticalSection(&critsec);
    }
    void ProcessTaskQueue()
    {
        while (true)
        {
            EnterCriticalSection(&critsec);
            ThreadWorker *thistask = taskqueue.front();
            taskqueue.pop_front();
            LeaveCriticalSection(&critsec);
            thistask->StartWorker();
        }
    }
    ~ThreadManager(void)
    {
        DeleteCriticalSection(&critsec);
    }
};

要将任务添加到队列,我们​​需要一个实现ThreadWorker的子类。

class SomeWorkerTask : public ThreadWorker
{
public:
SomeWorkerTask(void);
virtual ~SomeWorkerTask(void);

void RunTask()
{
    std::cout << "Hello, I am a worker task runing on thread id " << ThreadId << std::endl;
}
};

创建SomeWorkerTask的新实例并将其添加到队列中,然后处理队列。在你的情况下,你将有不同的线程向队列添加任务和处理队列,但我认为你会得到这个想法。

SomeWorkerTask *atask = new SomeWorkerTask();
ThreadManager manager;
manager.AddTaskToQueue(atask);
manager.ProcessTaskQueue();

如果您想知道任务何时完成处理,您可以从另一个线程调用ThreadWorker :: WaitUntilWorkerFinished或将调用添加到ProcessTaskQueue。您可以修改ThreadManager,以便拥有一个等待任务队列,一个正在运行的任务队列和一个已完成任务的第三个队列。将任务从等待队列中弹出后,将其添加到正在运行的队列中,并使用任务的信号量确定它何时完成,然后将其添加到已完成的任务/将其从正在运行的任务中删除。请注意,标准容器(如矢量,地图和列表)不是线程安全的,因此您应始终围绕使用互斥锁(例如临界区或互斥锁)插入/移除容器的操作。

希望有所帮助。

答案 1 :(得分:0)

你需要一个从多个线程同时访问的队列的互斥锁,并且由于你正在测试runningQueue.size() < 128,你还需要一个条件变量。如果您的编译器支持c ++ 11,std::mutexstd::condition_variable将完成工作,或者boost::mutexboost::condition_variable都可以。
所以它有点像这样:

onAcceptClient(int client_fd)
{
    boost::mutex::scoped_lock waitLock(mWaitMutex);
    waitQueue.insert(client_fd);
}  

while(1) // this must run in single thread
{
    boost::mutex::scoped_lock lock(mRunningMutex);
    // wait if the runningQueue.size >= 128
    while(runningQueue.size() >= 128)
        mRunningCond.wait(lock);

    if (runningQueue.size() < 128)
    {
        int diff = 128 - runningQueue.size() ;
        for (int a = 0; a < diff; a++)
        {
            boost::mutex::scoped_lock waitLock(mWaitMutex);
            int cfc = waitQueue.pop();
            worker w;
            w.run(cfc);
            runningQueue.insert(w);
        }
    }
}