转载并整理自 https://blog.csdn.net/qq_38231713/category_10001159.html
1 线程栈空间
我的 linux开发机上默认是8192 kbytes。
[admin@host]$ ulimit -s
8192
[admin@host]$ ulimit -a
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 1545653
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1048576
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 307200
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
2 并发
2.1 多进程并发
相同主机上的不同进程之间的通信方式:
- 管道
- 文件
- 消息队列
- 共享内存
不同主机上的进程的通信方式:
- socket通信技术
什么是管道?
管道是一种最基本的IPC(进程间通信)机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。
2.2 多线程并发
同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。
3 线程
主线程从 main() 函数开始执行,子线程也需要从一个函数开始运行(初始函数),一旦此函数运行完毕,该线程就结束了。
3.1 进程结束的标志
主线程执行完毕(子线程不论是否结束都会被终止,有例外情况)
3.2 创建线程
#include <iostream>
#include <thread>
using namespace std;
void SubThreadPrint() {
cout << "子线程开始运行" << endl;
cout << "子线程运行完毕" << endl;
return;
}
int main() {
// 创建线程
// 执行线程
thread my_thread(SubThreadPrint);
// 阻塞主线程
// 子线程执行完,主线程继续往下执行
my_thread.join();
// 主线程不再等待子线程
// 子线程与主线程失去关联,驻留在后台,由C++运行时库接管
// my_thread.detach();
// 判断是否可以成功使用 join() 或者 detach()
//如果返回 true,证明可以调用 join() 或者 detach()
//如果返回 false,证明调用过 join() 或者 detach(),join() 和 detach() 都不能再调用了
if (my_thread.joinable()) {
cout << "可以调用可以调用join()或者detach()" << endl;
} else {
cout << "不能调用可以调用join()或者detach()" << endl;
}
cout << "Hello World!" << endl;
return 0;
}
3.3 其他创建线程的方法
理论依据:
线程类参数是一个可调用对象。
一组可执行的语句称为可调用对象,C++中的可调用对象可以是函数、函数指针、lambda表达式、bind创建的对象或者重载了函数调用运算符的类对象。
3.3.1 创建类,重载函数调用运算符,初始化该类的对象,把该对象作为线程入口地址
#include <iostream>
#include <thread>
using namespace std;
class SubThreadClass {
public:
// 不能带参数
void operator()() {
cout << "子线程开始运行" << endl;
cout << "子线程运行完毕" << endl;
}
};
int main() {
SubThreadClass sub_thread_class;
// 创建线程
// 执行线程
thread my_thread(sub_thread_class);
// 阻塞主线程
// 子线程执行完,主线程继续往下执行
my_thread.join();
// 主线程不再等待子线程
// 子线程与主线程失去关联,驻留在后台,由C++运行时库接管
// my_thread.detach();
// 判断是否可以成功使用 join() 或者 detach()
//如果返回 true,证明可以调用 join() 或者 detach()
//如果返回 false,证明调用过 join() 或者 detach(),join() 和 detach() 都不能再调用了
if (my_thread.joinable()) {
cout << "可以调用可以调用join()或者detach()" << endl;
}
else {
cout << "不能调用可以调用join()或者detach()" << endl;
}
cout << "Hello World!" << endl;
return 0;
}
3.3.2 lambda 表达式创建线程
#include <iostream>
#include <thread>
using namespace std;
int main() {
auto lambda_thread = [] {
cout << "子线程开始执行了" << endl;
cout << "子线程开始执行了" << endl;
};
// 创建线程
// 执行线程
thread my_thread(lambda_thread);
// 阻塞主线程
// 子线程执行完,主线程继续往下执行
my_thread.join();
// 主线程不再等待子线程
// 子线程与主线程失去关联,驻留在后台,由C++运行时库接管
// my_thread.detach();
// 判断是否可以成功使用 join() 或者 detach()
//如果返回 true,证明可以调用 join() 或者 detach()
//如果返回 false,证明调用过 join() 或者 detach(),join() 和 detach() 都不能再调用了
if (my_thread.joinable()) {
cout << "可以调用可以调用join()或者detach()" << endl;
}
else {
cout << "不能调用可以调用join()或者detach()" << endl;
}
cout << "Hello World!" << endl;
return 0;
}
3.3.3 把某个类中的某个函数作为线程的入口地址
#include <iostream>
#include <thread>
using namespace std;
class Data_ {
public:
void GetMsg() {
cout << "GetMsg 子线程开始执行了" << endl;
cout << "GetMsg 子线程开始执行了" << endl;
}
void SaveMsg() {
cout << "SaveMsg 子线程开始执行了" << endl;
cout << "SaveMsg 子线程开始执行了" << endl;
}
};
int main() {
Data_ data;
// 第一个 & 是取址
// 第二个 & 是引用
thread my_thread1(&Data_::GetMsg, &data);
thread my_thread2(&Data_::SaveMsg, &data);
my_thread1.join();
my_thread2.join();
cout << "Hello World!" << endl;
return 0;
}
运行结果如下
SaveMsg 子线程开始执行了
SaveMsg 子线程开始执行了
GetMsg 子线程开始执行了
GetMsg 子线程开始执行了
Hello World!
C:\Users\null\source\repos\Project1\Debug\Project1.exe (进程 14644)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
4 线程传参
4.1 传递临时对象
4.1.1 陷阱1
#include <iostream>
#include <thread>
#include <windows.h>
using namespace std;
void SubThreadFunc( int& i, char* buf) {
// detach 之后,i 不是 var 真正的引用,实际上值传递
// 推荐使用 const int i
cout << i << endl;
// buf 指向原来的字符串,不安全的
cout << buf << endl;
}
int main() {
int var = 1;
char buf[] = "This is a test";
// 函数名 + 两个参数
thread my_thread(SubThreadFunc, var, buf);
my_thread.join();
// my_thread.detach();
cout << "Hello World!" << endl;
return 0;
}
4.1.2 陷阱2