前面使用 GCC 4.7, MinGW4.7 以及 boost 在 windows, Ubuntu下测试了C++11 的新特性,这次,把 Ubuntu 下的C++11测试代码直接挪到Windows 8 + Visual Stuido 2012 Express下,支持还是比较好的!测试环境:WIndows XP Host + Vmbox 4.2 +windows 8 企业试用版, visual studio 2012 Express for Windows Desktop,
顺便提一下,WIndows8 速度不错,虚拟机下 跑 VStudio 还很快的。
测试内容:
1、std::thread, 条件变量、mutex
2、lamda表达式,function, std::bind
3、nullptr类型
4、foreach (在algorithm里)
至于0x里已经有的 std::move, auto, regex, tumple等就算了。
#include "stdafx.h"
#include <iostream>
#include <thread>
#include <mutex>
#include <functional>
#include <list>
#include <atomic>
#include <vector>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <memory>
#include <condition_variable>
#include <algorithm>
//This class defines a class contains a thread, a task queue
class cpp11_thread
{
public:
cpp11_thread()
:m_b_is_finish(false)
,m_pthread(nullptr)
{
}
~cpp11_thread()
{
m_list_tasks.clear();
if (m_pthread!=nullptr)
delete m_pthread;
}
public:
//wait until this thread is terminated;
void join() {
terminate();
if (m_pthread!=nullptr)
m_pthread->join();
}
//wait until this thread has no tasks pending.
void wait_for_idle()
{
while(load())
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
//set the mask to termminiate
void terminate() {
m_b_is_finish = true;
m_cond_incoming_task.notify_one();
}
//return the current load of this thread
size_t load()
{
size_t sz = 0;
m_list_tasks_mutex.lock();
sz = m_list_tasks.size();
m_list_tasks_mutex.unlock();
return sz;
}
//Append a task to do
size_t append(std::function< void (void) > func)
{
if (m_pthread==nullptr)
m_pthread = new std::thread(std::bind(&cpp11_thread::run,this));
size_t sz = 0;
m_list_tasks_mutex.lock();
m_list_tasks.push_back(func);
sz = m_list_tasks.size();
//if there were no tasks before, we should notidy the thread to do next job.
if (sz==1)
m_cond_incoming_task.notify_one();
m_list_tasks_mutex.unlock();
return sz;
}
protected:
std::atomic< bool> m_b_is_finish; //atomic bool var to mark the thread the next loop will be terminated.
std::list<std::function< void (void)> > m_list_tasks; //The Task List contains function objects
std::mutex m_list_tasks_mutex; //The mutex with which we protect task list
std::thread * m_pthread; //inside the thread, a task queue will be maintained.
std::mutex m_cond_mutex; //condition mutex used by m_cond_locker
std::condition_variable m_cond_incoming_task; //condition var with which we notify the thread for incoming tasks
protected:
void run()
{
// loop wait
while (!m_b_is_finish)
{
std::function< void (void)> curr_task ;
bool bHasTasks = false;
m_list_tasks_mutex.lock();
if (m_list_tasks.empty()==false)
{
bHasTasks = true;
curr_task = *m_list_tasks.begin();
}
m_list_tasks_mutex.unlock();
//doing task
if (bHasTasks)
{
curr_task();
m_list_tasks_mutex.lock();
m_list_tasks.pop_front();
m_list_tasks_mutex.unlock();
}
if (!load())
{
std::unique_lock< std::mutex> cond_locker(m_cond_mutex); //using this lock to wait for signals;
m_cond_incoming_task.wait_for(cond_locker,std::chrono::milliseconds(500));//m_cond_incoming_task.wait(m_cond_locker);
}
}
}
};
//the thread pool class
class cpp11_thread_pool
{
public:
cpp11_thread_pool(int nThreads)
:m_n_threads(nThreads)
{
assert(nThreads>0 && nThreads<=512);
for (int i = 0; i< nThreads ;i++)
m_vec_threads.push_back(std::shared_ptr<cpp11_thread>(new cpp11_thread()));
}
~cpp11_thread_pool()
{
}
public:
//total threads;
size_t count(){return m_vec_threads.size();}
//wait until all threads is terminated;
void join()
{
std::for_each(m_vec_threads.begin(),m_vec_threads.end(),[this](std::shared_ptr<cpp11_thread> & item)
{
item->terminate();
item->join();
});
}
//wait until this thread has no tasks pending.
void wait_for_idle()
{
int n_tasks = 0;
do
{
if (n_tasks)
std::this_thread::sleep_for(std::chrono::milliseconds(200));
n_tasks = 0;
std::for_each(m_vec_threads.begin(),m_vec_threads.end(),[this,&n_tasks](std::shared_ptr<cpp11_thread> & item)
{
n_tasks += item->load();
});
}while (n_tasks);
}
//set the mask to termminiate
void terminate()
{
std::for_each(m_vec_threads.begin(),m_vec_threads.end(),[this](std::shared_ptr<cpp11_thread> & item)
{
item->terminate();
});
}
//return the current load of this thread
size_t load(unsigned int n)
{
return (n>=m_vec_threads.size())?0:m_vec_threads[n]->load();
}
//Append a task to do
void append(std::function< void (void) > func)
{
int nIdx = -1;
unsigned int nMinLoad = -1;
for ( int i=0;i<m_n_threads;i++)
{
if (nMinLoad> m_vec_threads[i]->load())
{
nMinLoad = m_vec_threads[i]->load();
nIdx = i;
}
}
assert(nIdx>=0 && nIdx<m_n_threads);
m_vec_threads[nIdx]->append(func);
}
protected:
//NO. threads
int m_n_threads;
//vector contains all the threads
std::vector<std::shared_ptr<cpp11_thread> > m_vec_threads;
};
//a function which will be executed in sub thread.
void hello()
{
//sleep for a while
std::this_thread::sleep_for(std::chrono::milliseconds(rand()%900+100));
std::cout <<
"Hello world, I'm a function runing in a thread!"
<< std::endl;
}
//a class has a method, which will be called in a thread different from the main thread.
class A
{
private:
int m_n;
public:
A(int n)
:m_n(n)
{}
~A(){}
public:
void foo (int k)
{
//sleep for a while
std::this_thread::sleep_for(std::chrono::milliseconds(rand()%900+100));
std::cout <<"n*k = "<<k*m_n<<std::endl;
m_n++;
}
};
//let's test the thread.
int main()
{
cpp11_thread_pool thread(2);
srand((unsigned int)time(0));
A a(1),b(2),c(3);
int nsleep = rand()%900+100;
//append a simple function task
thread.append(&hello);
//append lamda
thread.append
(
[&nsleep]()
{
std::this_thread::sleep_for(std::chrono::milliseconds(rand()%900+100));
std::cout<<"I'm a lamda runing in a thread"<<std::endl;
}
);
//append object method with copy-constructor(value-assignment)
thread.append(std::bind(&A::foo,a,10));
thread.append(std::bind(&A::foo,b,11));
thread.append(std::bind(&A::foo,c,12));
thread.append(std::bind(&A::foo,a,100));
//append object method with address assignment, will cause the objects' member increase.
thread.append(std::bind(&A::foo,&a,10));
thread.append(std::bind(&A::foo,&b,11));
thread.append(std::bind(&A::foo,&c,12));
thread.append(std::bind(&A::foo,&a,100));
//wait for all tasks done.
thread.wait_for_idle();
//kill
thread.terminate();
//wait for killed
thread.join();
//test function
std::function < void (void) > func1 = &hello;
std::function < void (void) > func2 = &hello;
if (func1.target<void (void) >()!=func2.target<void (void)>())
return 0;
else
return 1;
}