在之前的学习过程中,关于多线程服务器编程的学习内容主要在Linux上的C语言实现,例如pthread_create,等函数,如今C++11也有很多支持多线程的函数和方法(当然环境选择Linux或者Windows都是可以的),并且更加高效和灵活,学无止境,从这次开始,进入到C++11多线程服务器编程开发的学习中。
C++11提供的的多线程编程接口
高级接口:future,async
低级接口:thread,mutex
#include <vector>
#include <iostream>
#include <iomanip>
#include <thread>
#include <chrono>
#include <future>
#include <cmath>
#include <string>
#include <cstdlib>
#include <unordered_map>
#include <algorithm>
/*
at the STD namespace,thread class is a way to create Thread,in my Example,work is a thread object
work.join well block the MainThread and ask the "work" thread if over,if the "work" thread is over
the program well continue to run,otherwise,it well always block
*/
void HelloWord()
{
std::cout << "Hello Work Thread!" << std::endl;
}
int main()
{
std::thread work(HelloWord);
std::cout << "Hello Main Thread!" << std::endl;
work.join();
return 0;
}
为什么使用多线程
1.随着时代的发展,CPU单核红利已经结束,服务器开发使用多线程大势所趋。
2.多线程有着自身的优势,能有效利用多核计算机的性能。
3.实践验证理论,理论反推动实践,如今操作系统、标准库和第三方库都支持了多线程的API,使用更加方便。
4.多线程和异步I/O的关系,单线程是阻塞I/O,如果操作I/O很耗费时间,势必拖累整体速度,但是多线程不会有这种情况。
#include <vector>
#include <iostream>
#include <iomanip>
#include <thread>
#include <chrono>
#include <future>
#include <cmath>
#include <cstdlib>
#include <algorithm>
//if you need to updata the new work setting,please select The Tools menu and choose "Get Tools and Function" Option
//Learn some useful tips
//std::cout <<typeid(b).name() << std::end; // cout:int typeid could output the value type
void Function()//This is "auto& i" diofferent with "auto i"
{
std::string str1 = "hello";
std::string str2 = "hello";
for (auto i : str1)
{
i = toupper(i);
}
std::cout << str1 << std::endl;
for (auto& i : str2)
{
i = toupper(i);
}
std::cout << str2 << std::endl;
}
//Attention:when a value's type is cite,if we use auto ,it isn't be a cite,for Example
void Function_2()
{
int A = 1;
int& F = A;
auto B = F;//typeid(B).name()-> int
auto& C = F;//typeid(C).name()-> int&
std::cout << typeid(B).name() << std::endl;
std::cout << typeid(C).name() << std::endl;
}
void Function_3()
{
const int A = 1;
auto B = A;//typeid(B).name()-> int
const int C = A;
auto& D = C;//typeid(D).name()-> const int
std::cout << typeid(B).name() << std::endl;
std::cout << typeid(C).name() << std::endl;
}
//about Multithread test
double Math_algorithm(double value)
{
if (value <= 0)return value;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
return sqrt(sqrt(value * (value - 3)) * value);
}
template<typename Iter,typename Fun>
double Count_up(std::thread::id id,Iter iterBegin, Iter iterEnd, Fun func)
{
auto this_id = std::this_thread::get_id();
if (id == this_id)
{
std::cout << "This is MainThreadId:" << id << std::endl;
}
else
{
std::cout << "This is WorkThreadId:" << this_id << std::endl;
}
double value = double();
for (auto iter = iterBegin; iter != iterEnd; iter++)
{
value += func(*iter);
}
return value;
}
int main()
{
Function();
auto MainThreadId = std::this_thread::get_id();
std::vector<double> db;
for (int i = 0; i < 1000; i++)
{
db.push_back(rand());
}
std::cout << db.size() << std::endl;
double Value = double();
auto start = clock();
for (auto& Type : db)
{
Value += Math_algorithm(Type);
}
//Singlethread pass the test only use a thread
auto end = clock();
size_t size = db.size();
std::cout << "Single thread" << Value <<"It use:"<<(end - start)<< std::endl;
end = clock();
//in my setting ,Multithread pass the test use two threads
//cut down the vector
auto AntherIter = db.begin() + size;
double AntherValue = double();
//at the MainThread
double MainHalfValue = Count_up(MainThreadId, db.begin(), AntherIter, Math_algorithm);
auto IterEnd = db.end();
//at the WorkThread
//Important to Learn it ---- MULTITHREAD
std::thread s([&AntherValue, MainThreadId, AntherIter, IterEnd](){
AntherValue = Count_up(MainThreadId, AntherIter, IterEnd, Math_algorithm);
});
//clear up the pthread
s.join();
start = clock();
std::cout << "Multithread" << AntherValue + MainHalfValue << "It use:" << (start - end) << std::endl;
return 0;
}
在这里,我使用到了for(auto& value:Type)的遍历方式,这与一般的for(auto value:Type)是不同的,在Function函数中,作出了一个示例来展示他们的不同,使用auto&可以对容器的内容进行修改和更新,这是auto&的隐含功能,在我Main实际操作中,auto&这样写,更加普适罢了,auto也是可以的,这里指出来auto和auto&是由区别的,希望大家知晓。
用到了chrono,future,thread这些C++11的头文件,建议本机使用的VS版本在2012以上。
C++11有许多新特性,比如默认的函数比起C++98要多出移动拷贝构造函数和移动赋值函数,这些新的特性之后会慢慢学习到,现在先从多线程的基础入手,循序渐进。