Vue框架:
从项目学Vue
OJ算法系列:
神机百炼 - 算法详解
Linux操作系统:
风后奇门 - linux
#include
void *func(void *args){
char* name = (char*)args;
cout<<name<<pthread_self()<<endl;
cout<<"线程任务函数"<<endl;
}
int main(){
pthread_t tid;
if(pthread_create(&tid, nullptr, func, "linux线程 : ") < 0){
cout<<"线程创建失败"<<endl;
}
return 0;
}
#include
void *func(void *args){
cout<<"线程任务函数"<<endl;
}
int main(){
pthread_t tid;
pthread_create(&tid, nullptr, func, nullptr) < 0);
pthread_join(tid, nullptr);
return 0;
}
#include
void *func(void *args){
pthread_detach(pthread_self());
cout<<"线程任务函数"<<endl;
}
int main(){
pthread_t tid;
pthread_create(&tid, nullptr, func, nullptr) < 0);
return 0;
}
#include
void *func(void *args){
cout<<"线程任务函数"<<endl;
//return (void*)&"0";
return (void*)"0";
}
int main(){
pthread_t tid;
pthread_create(&tid, nullptr, func, nullptr) < 0);
void* exit_code;
pthread_join(tid, &exit_code);
cout<<*(int*)exit_code<<endl;
return 0;
}
#include
void *func(void *args){
pthread_detach(pthread_self());
cout<<"线程任务函数"<<endl;
int *p = new int(0);
pthread_exit((void*)p);
}
int main(){
pthread_t tid;
pthread_create(&tid, nullptr, func, nullptr) < 0);
void* ret;
pthread_join(func, &ret);
cout<<*(int*)ret<<endl;
return 0;
}
他人pthread_cancel():
被cancel终止的线程,退出码都是常量PTHREAD_CANCELED
#include
void *func(void *args){
pthread_detach(pthread_self());
while(1){
cout<<"线程任务函数"<<endl;
sleep(1);
}
}
int main(){
pthread_t tid;
pthread_create(&tid, nullptr, func, nullptr) < 0);
sleep(3);
pthread_cancel(tid);
void* ret;
pthread_join(tid, &ret);
cout<<*(int*)ret<<endl;
if(*(int*)ret == PTHREAD_CANCELED){
printf("thread PTHREAD_CANCELED\n");
}else{
printf("thread isn't pthread_canceled\n");
}
return 0;
}
虽然上述的 #include
但是毕竟该库不是一个官方库,未自动添加到环境变量中
别忘了我们使用g++ / gcc编译时,总要携带命令行参数-lpthread
这个易忘问题终于在C++11得到了解决,官方线程库 #include < thread>来了
#include
thread t(可调用对象,可调用对象参数);
#include
#include
using namespace std;
void func(int a, int b){
cout<<a <<" " <<b <<endl;
}
int main(){
thread t(func, 1, 2);
return 0;
}
#include
#include
using namespace std;
void func(int a, int b){
cout<<a <<" " <<b <<endl;
}
int main(){
thread t(func, 1, 2);
t.join();
return 0;
}
#include
#include
using namespace std;
struct Func{
void operator()(int a, double b){
cout<<a <<" " <<b <<endl;
}
};
int main(){
thread t(Func(), 1, 2);
t.join();
return 0;
}
#include
#include
using namespace std;
int main(){
int x = 1, y = 2;
thread t([](int a, int b){
cout<<a <<" " <<b <<endl;
}, x, y);
return 0;
}
#include
#include
using namespace std;
int main(){
int x = 1, y = 2;
thread t([](int *a, int *b){
*a = 3;
cout<<"子线程 :" <<*a <<" " <<*b <<endl;
}, &x, &y);
cout<<"主线程 :"<<x<<endl;
return 0;
}
运行结果:
发现只有子线程中的变量发生值的变化,而主线程没有
难道开辟在主线程中的变量x y不被所有线程共享吗?
子线程重新在进程共享区开辟了变量空间,发生类似写实拷贝了吗?
继续看下面的代码:
原来是主线程调度优先级总是比子线程高
导致子线程尚未修改变量,主线程已经打印完成
符合所有线程共享进程绝大部分内容
线程自己的局部变量以不同tid的结构体存储在进程地址空间的共享区
大多数编译器直接传参左值引用会报错,
visual studio 13不会,但是会直接视为传值
传左值引用 + ref()函数,可以实现多线程看到同一块内存:
#include
#include
#include
using namespace std;
int main(){
int x = 0;
thread t([](int &n){
n = 1;
cout<<"子线程:"<<n<<endl;
}, ref(x));
sleep(1);
cout<<"主线程:"<<x<<endl;
return 0;
}
#include
#include
using namespace std;
int main(){
int x = 0, y = 1;
thread t([&](){
x = 2;
cout<<"子线程:"<<x <<" "<<y<<endl;
});
cout<<"主线程"<<x <<" "<<y <<endl;
return 0;
}
thread 变量.join():
一行代码让主线程陷入等待,
若不加join(),主线程创建完子线程后,继续向下运行
遇到return时马上终止该进程及其内部所有线程
子线程可能尚未运行结束就被强迫终止
#include
#include
#include
using namespace std;
void func(){
while(1){
cout<<"子线程脱离,但是主线程不要释放资源"<<endl;
sleep(1);
}
}
int main(){
thread (func).detach();
sleep(3);
return 0;
}
#include
#include
#include
#include
using namespace std;
int main(){
int N, M;
cin >>N >>M;
atomic<int> x; //原子变量可视为自带锁的变量
x = 0; //原子变量不能初始化构造,但是可以赋值拷贝构造
vector<thread> vthds;
vthds.resize(N);
atomic<int> costTime;
costTime = 0;
for(int i=0; i<vthds.size(); i++){
vthds[i] = thread([M, &x, &costTime]{
int begin = clock();
for(int i=0; i<M; i++){
cout<<this_thread::get_id()<<"->"<<x<<endl;
x++;
}
int end = clock();
costTime += (end - begin);
});
}
for(auto &e: vthds){
e.join();
}
cout<<x<<endl;
cout<<"CostTime : "<<costTime;
return 0;
}
#include
pthread_mutex_t mutex;
int main(){
//动态初始化:
pthread_mutex_init(&mutex, nullptr);
//加锁:
pthread_mutex_lock(&mutex);
//解锁:
pthread_mutex_unlock(&mutex);
//销毁锁:
pthread_mutex_destory(&mutex);
}
#include
//创建锁:
mutex mtx;
//加锁:
mtx.lock();
//解锁:
mtx.unlock();
//不必销毁锁:
#include
#include
#include
using namespace std;
int x = 0;
mutex mtx;
int N = 10000000;
void func(){
//加锁位置2:mtx.lock()
for(int i=0; i<N; i++){
//加锁位置1:mtx.lock()
++x;
//解锁位置1:mtx.unlock()
}
//解锁位置2:mtx.unlock()
}
int main(){
thread t1(func);
thread t2(func);
return 0;
}
位置1的效果:
每次进程调度中存在多次循环
每次循环都申请释放一次锁
每次申请释放锁的主要任务只是+1
位置2的效果:
每次进程调度中存在多次循环
所有循环只申请释放一次锁
每次申请释放锁的主要任务是重复几万次+1
显然,位置2的速度更快,资源消耗更少,且同样保证了线程安全
当业务代码比较简单,执行速度块,执行时间短时:
将锁加在循环外,避免循环内部不断申请释放锁的资源浪费
当业务代码比较复杂,执行速度慢,执行时间长时:
将锁加载循环内,一方面一次线程调度内可能完不成一次业务代码
另一方面申请释放锁的消耗相对业务代码的消耗来说可以忽略了