传统的C++(C++11标准之前)中并没有引入线程这个概念,在C++11出来之前,如果我们想要在C++中实现多线程,需要借助操作系统平台提供的API,比如Linux的,或者windows下的 。
本文详细介绍C++11 线程库的基本使用,包括如何创建线程、启动线程、等待线程完成、如何分离线程。
线程:进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。
进程:进程就是运行中的程序
线程安全:不论运行多少次,如果多线程程序每一次运行的结果都跟单线程运行的结果是始终如一的,那么表名你的线程是安全的。
线程函数:默认情况下我们所写的代码都是只有一个线程的,而这个线程的入口函数是main() 函数, 这是系统默认的。而我们创建的另一个线程也需要一个函数来进入, 这个函数叫做线程函数。
示例1:
//多线程好处
//任务分解:耗时的操作,任务分解,实时响应
//数据分解:充分利用多核CPU处理数据
//数据流分解:读写分离,解耦合设计
//linux lpthread
//要创建线程,我们需要一个可调用的函数或函数对象,作为线程的入口点。
//在C++11中我们可以使用函数指针、函数对象或lambda表达式来实现。创建线程的基本语法如下!
//C++11 Thread线程库的基本使用
//创建线程 启动线程 等待线程 完成线程分离
//要创建线程,我们需要一个可调用的函数或函数对象,作为线程的入口点
#include
#include
void printHelloWorld()
{
std::cout << "Hello World!" << std::endl;
}
int main()
{
//1.创建线程
std::thread thread1(printHelloWorld);
return 0;
}
如果是在单线程下,启动线程后,主程序不会等待子线程执行完函数。所以会报错。
#include
#include
void printHelloWorld()
{
std::cout << "Hello World!" << std::endl;
}
int main()
{
//1.创建线程
std::thread thread1(printHelloWorld);
thread1.join();
return 0;
}
#include
#include
#include
void printHelloWorld(std::string msg)
{
//std::cout << "Hello World!" << std::endl;
std::cout << msg << std::endl;
}
int main()
{
//1.创建线程
std::thread thread1(printHelloWorld, "Hello World!");
thread1.join();
return 0;
}
#include
#include
#include
void printHelloWorld(std::string msg)
{
//std::cout << "Hello World!" << std::endl;
std::cout << msg << std::endl;
}
int main()
{
//1.创建线程
std::thread thread1(printHelloWorld, "Hello World!");
//thread1.join();//等待线程执行完毕后再继续往下执行
thread1.detach();//分离线程,主线程执行完毕,子线程在后台持续运行
return 0;
}
#include
#include
#include
void printHelloWorld(std::string msg)
{
//std::cout << "Hello World!" << std::endl;
std::cout << msg << std::endl;
}
int main()
{
//1.创建线程
std::thread thread1(printHelloWorld, "Hello World!");
//thread1.join();//等待线程执行完毕后再继续往下执行
//thread1.detach();//分离线程,主线程执行完毕,子线程在后台持续运行
bool idJoin = thread1.joinable();
if (idJoin)
{
thread1.join();//等待线程执行完毕后再继续往下执行
}
return 0;
}
如果说我们对一个不能够调用join()或者detach()的线程进行强行调用,程序报错systerm_error
#include
#include
#include
void printHelloWorld(std::string msg)
{
//std::cout << "Hello World!" << std::endl;
//std::cout << msg << std::endl;
for (int i = 0; i < 10000; i++)
std::cout << i << std::endl;
}
int main()
{
//1.创建线程
std::thread thread1(printHelloWorld, "Hello World!");
//thread1.join();//等待线程执行完毕后再继续往下执行
//thread1.detach();//分离线程,主线程执行完毕,子线程在后台持续运行
bool idJoin = thread1.joinable();
if (idJoin)
{
thread1.join();//等待线程执行完毕后再继续往下执行
}
std::cout << "over" << std::endl;
return 0;
}
#include
#include
void foo(int &x)
{
x = x + 1;
}
int main()
{
std::thread t(foo, 1);//传递临时变量
t.join();
return 0;
}
修改为
#include
#include
void foo(int &x)
{
x = x + 1;
}
int main()
{
int a = 1;
std::thread t(foo, std::ref(a));//传递临时变量
t.join();
std::cout << "a=" << a << std::endl;
return 0;
}
#include
#include
void foo(int *x)
{
*x = *x + 100;
}
int main()
{
int a = 1;
std::thread t(foo, &a);//传递临时变量
t.join();
std::cout << "a=" << a << std::endl;
return 0;
}
#include
#include
std::thread t;
int a = 1;
void foo(int *x)
{
*x = *x + 1;
std::cout << "*x=" << *x << std::endl;
}
void test()
{
//int a = 1;
t = std::thread(foo, &a);
}
int main()
{
test();
t.join();
//std::cout << "a=" <
std::cout << "over" << std::endl;
return 0;
}
#include
#include
void foo(int& x)
{
std::cout << x << std::endl; // 访问已经被释放的内存
}
int main()
{
int* ptr = new int(1);
std::thread t(foo, *ptr); // 传递已经释放的内存
delete ptr;
t.join();
return 0;
}
#include
#include
class MyClass
{
public:
void func()
{
std::cout << "Thread " << std::this_thread::get_id()
<< " started" << std::endl;
// do some work
std::cout << "Thread " << std::this_thread::get_id()
<< " finished" << std::endl;
}
};
int main()
{
MyClass obj;
std::thread t(&MyClass::func, &obj);
// obj 被提前销毁了,会导致未定义的行为
return 0;
}
上面的代码中,在创建线程之后,obj 对象立即被销毁了,这会导致在线程执行时无法访问 obj 对象,可能会导致程序崩溃或者产生未定义的行为。
为了避免这个问题,可以使用 std::shared_ptr 来管理类对象的生命周期,确保在线程执行期间对象不会被销毁。具体来说,可以在创建线程之前,将类对象的指针封装在一个 std::shared_ptr 对象中,并将其作为参数传递给线程。这样,在线程执行期间,即使类对象的所有者释放了其所有权,std::shared_ptr 仍然会保持对象的生命周期,直到线程结束。
以下是使用 std::shared_ptr 修复上面错误的示例:
#include
#include
#include
class MyClass
{
public:
void func()
{
std::cout << "Thread " << std::this_thread::get_id()
<< " started" << std::endl;
// do some work
std::cout << "Thread " << std::this_thread::get_id()
<< " finished" << std::endl;
}
};
int main()
{
std::shared_ptr<MyClass> obj = std::make_shared<MyClass>();
std::thread t(&MyClass::func, obj);
t.join();
// obj 被提前销毁了,会导致未定义的行为
return 0;
}
//5.入口函数为类的私有成员函数
#include
#include
class MyClass
{
private:
friend void myThreadFunc(MyClass* obj);
void privateFunc()
{
std::cout << "Thread "
<< std::this_thread::get_id() << " privateFunc" << std::endl;
}
};
void myThreadFunc(MyClass* obj)
{
obj->privateFunc();
}
int main() {
MyClass obj;
std::thread thread_1(myThreadFunc, &obj);
thread_1.join();
return 0;
}