线程与进程优缺点对比:
多线程开销小,但难于管理,且不能用于分布式系统;
多进程开销大,操作系统会进行一部分管理,因此用户管理就比较简单,可用于分布式;
通常多线程和多进程结合使用。
参考资料:http://edu.youkuaiyun.com/course/detail/2303/35894?auto_start=1
代码实例:
1 最简单的多线程
#include <iostream>
#include <thread>
void function_1()
{
std::cout <<"www.oxox.work"<<std::endl;
}
int main() //主线程
{
std::thread t1(function_1); //创建并初始化一个线程,且线程t1创建完之后就开始运行
//t1.detach(); //主线程和t1线程互不影响,detach可以使主线程不等待t1线程结束即可运行,这样会使得程序的运行结果没有内容输出,因为主线程还没有等到t1输出内容就结束了。线程被deatch之后就不能再join了,如果再join,编译不会报错,但是运行会报错
if(t1.joinable()) //如果执行了t1.detach(),t1.joinable()为false
{
t1.join(); //主线程将等待t1线程结束后再运行
}
return 0;
}
2 主线程和子线程交叉运行
#include <iostream>
#include <thread>
using namespace std;
void function_1()
{
cout <<"www.oxox.work"<<endl;
}
class Factor
{
public:
void operator()()
{
for(int i = 0; i > -100; --i)
{
cout << "from t1: " << i << endl;
}
}
};
int main() //主线程
{
//std::thread t1(function_1); //使用函数创建并初始化一个线程,且线程开始运行
Factor fct;
std::thread t1(fct); //使用函数对象创建并初始化一个线程
try
{
for(int i = 0; i < 100; ++i)
{
cout << "from main: " << i << endl;
}
}
catch(...) //上面的for循环属于主线程,如果上面抛出异常,但是没有try catch,主线程终止,t1线程也终止了,这样是非线程安全的。添加try catch之后,即使主线程异常,t1线程也能正常执行结束
{
t1.join(); //主线程将等待t1线程结束后再运行
throw;
}
return 0;
}
3 主线程和子线程之间实现内存共享
#include <iostream>
#include <thread>
#include <string>
using namespace std;
void function_1()
{
cout <<"www.oxox.work"<<endl;
}
class Factor
{
public:
void operator()(string &s)
{
cout << "from t1: " << s << endl;
s = "I love XuHuanDaXue";
}
};
int main() //主线程
{
string s("I love www.oxox.work"); //string变量s被主线程和t1线程使用,可通过s实现内存共享
Factor fct;
//std::thread t1(fct, s); //这种方式并不能在t1线程中改变s,因为s将被拷贝
std::thread t1(fct, std::ref(s)); //t1线程可改变s,因为参数是s的引用
t1.join();
cout << "from main: " << s.c_str() << endl; //主线程使用了被t1线程改变的s
return 0;
}
4 线程移动与线程ID
#include <iostream>
#include <thread>
#include <string>
using namespace std;
void function_1()
{
cout <<"www.oxox.work"<<endl;
}
class Factor
{
public:
void operator()(string &s)
{
cout << "from t1: " << s << endl;
s = "I love XuHuanDaXue";
}
};
int main() //主线程
{
string s("I love www.oxox.work");
Factor fct;
cout << std::this_thread::get_id() << endl; //获取主线程ID,每个线程都有个ID
std::thread t1(fct, std::move(s)); //此处s被移动,移动操作比拷贝要高效,比引用要安全
std::thread t2=std::move(t1); //线程对象只能被移动,但不能被拷贝,所以必须使用std::move()
cout << t2.get_id() << endl; //获取t2线程ID
//t1.join();
t2.join(); //t1被移动到t2,t1已经是空的了,所以得使用t2.join()
cout << "from main: " << s.c_str() << endl;
cout << std::thread::hardware_concurrency() <<endl; //检测CPU能支持的最大线程数,如果用户创建的线程数超过了CPU能支持的,反而会引起性能下降
return 0;
}
5 线程安全
下面的代码是非线程安全的,主线程和t1线程将竞争资源cout,只要竞争到资源就随时可以将内容写入到输出流cout,使得输出看起来是下面这样的:
from t1: 0
from t1: -1
from t1: -2
from main: 0
from main: 1
from main: 2
from main: 3
from main: 4
from main: 5
from main: 6
from main: 7
from t1: -3
from t1: -4
from t1: -5
#include <iostream>
#include <thread>
#include <string>
using namespace std;
void function_1()
{
for(int i = 0; i > -100; --i)
{
cout << "from t1: " << i << endl;
}
}
int main() //主线程
{
std::thread t1(function_1);
for(int i = 0; i < 100; ++i)
{
cout << "from main