- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
程序运行起来,生成一个进程,该进程所属的主线程开始自动运行;main()函数就是主线程,main()函数返回,则整个进程执行完毕。
主线程从main()开始执行,所以自己创建的线程,也需要从一个函数(初始函数)开始运行,一旦这个函数运行完毕,就代表着这个线程运行结束。
整个进程是否执行完毕的标志是主线程是否执行完,如果主线程执行完毕了,就代表整个进程执行完毕了!
此时,一情况下:如果其他子线程还没有执行完毕,那么这些子线程也会被操作系统强行终止。
所以,一船情况下,得到一个结论:如果想保持子线程(自己用代码创建的线程)的运行状态的话,那么要让主线程一直保持运行,不要让主线程运行完毕。
[这条规则也有例外,后续会解这种例外,目前先这样理解和记忆]
编写多线程程序条件:
a)包含一个头文件<thread>
b)初始函数。
c)main中创建子线程
大家必须明确一点:有两个线程在跑,相当于整个程序的执行有两条线在同时走,所以,可以同时干两个事,即使一条线被堵住了,另外一条线是可以通行的,这就是多线程。
加入/汇合,说白了就是阻塞,阻塞主线程,让主线程等待子线程执行完毕,子线程和主线程汇合,然后主线程再往下走!
如果主线程执行完毕了,但子线程没执行完毕,这种程序不台格的;
一个书写良好的程序,应该是主线程等待子线程执行完毕后,自己才能最终退出。
传统多线程程序主线程要等待子线程执行完毕,然后自己再最后退出;
detach:分离,也就是主线程不和子线程汇合了,你主线程执行你的,我子线程执行我的,你主线程也不必等我子线程运行结束,主线程可以先执行结束,这并不影响子线程的执行。
为什么引入detach():我们创建了很多子线程,让主线程逐个等待子线程结束,这种编程方法不太好,所以引入了detach();
一旦detach()之后,与这个主线程关联的thread对象就会失去与这个主线程的关联,此时这个子线程就会驻留在后台运行(主线程与子线程失去联系)
这个子线程就相当于被C++运行时库接管,当这个子线程执行完成后,由运行时库负责清理该线程相关的资源(守护线程)
detach()使线程去自己的控制。
#include<iostream>
#include<thread>
using namespace std;
void myprint()
{
cout <<"线程开始执行了!" << endl;
cout << "线程执行结束了!" << endl;
}
int main()
{
//myprint可调用对象。
//(1)创建了线程,线程执行起点(入口)myprint();(2)myprint线程开始执行。
thread myobj(myprint);
//阻塞主线程并等待myprint子线程执行完
//主线程阻塞到这里等待myprint()执行完,当子线程执行完毕,这个join()就执行完毕,主线程就继续往下执行
myobj.join();
//myobj.detach(); //一旦调用detach(),就不能再使用join(),否则系统会报告错误;detach()应用比较少!
cout << "主线程执行!" << endl;
system("pause");
return 0;
}
判断是否可以使用join()或者detach()的;返回true(可以join或者detach)。
#include<iostream>
#include<thread>
using namespace std;
void myprint()
{
cout << "线程开始执行了!" << endl;
cout << "线程执行结束了!" << endl;
}
int main()
{
thread myobj(myprint);
if (myobj.joinable())
{
cout << "1:myobj.joinable() == true" << endl;
myobj.join();
}
else
{
cout << "1:myobj.joinable() == false" << endl;
}
if (myobj.joinable())
{
cout << "2:myobj.joinable() == true" << endl;
myobj.detach();
}
else
{
cout << "2:myobj.joinable() == false" << endl;
}
cout << "主线程执行!" << endl;
system("pause");
return 0;
}
大家可能还有一个疑问:一旦调用了detach(),那我主线程执行结束了,这里用的这个ta对象还在吗?(对象不在了)
解释:实际上这个对象是被 复制 到线程中去;执行完主线程后,ta会被销毁,但是所复制的TA对象依旧存在,所以只要这个Ta类对象没有引用,没有指针,那么就不会产生问题。
#include<iostream>
#include<thread>
using namespace std;
//类中包含operator(),此类的对象为可调用对象
class Ta
{
public:
int &m_i;
Ta(int &i) : m_i(i)
{
cout << "Ta()构造函数被执行了!" << endl;
};
Ta(const Ta &ta):m_i(ta.m_i)
{
cout << "Ta()复制构造函数被执行了!" << endl;
}
~Ta()
{
cout << "~Ta()析构函数被执行了!" << endl;
}
void operator()()
{
cout << "我的线程operator()开始执行了!"<< endl;
cout << "我的线程operator()执行结束了!" << endl;
cout << "m_i的值为:" << m_i <<endl;
}
};
int main()
{
int myi = 6;
Ta ta(myi);
thread myobj(ta);//ta可调用对象
//myobj.join(); //等待子线程执行结束
//此时,如果主线程执行完了,myi就被释放了;子线程还没执行完,就会出现不可预料的bug;
//myobj.detach();
cout << "主线程执行!" << endl;
system("pause");
return 0;
}
#include<iostream>
#include<thread>
using namespace std;
//类中包含operator(),此类的对象为可调用对象
int main()
{
auto myLamdba = [] {
cout << "我的线程开始执行了"<< endl;
cout << "我的线程执行结束了" << endl;
};
thread myobj(myLamdba);//ta可调用对象
myobj.join(); //等待子线程执行结束
cout << "主线程执行!" << endl;
system("pause");
return 0;
}
注:该文是C++11并发多线程视频教程笔记,详情可学习:https://study.163.com/course/courseMain.htm?courseId=1006067356
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!