二、线程创建、结束

一、使用函数创建线程

1、thread

主线程从main开始,我们创建的线程也要从一个函数(初始函数)开始运行,函数结束,这个线程结束;

主线程执行完毕,代表整个进程执行完毕;

如果子线程还没执行完毕,一般情况下,这些子线程会被强行终止;

1.#include <iostream>
2.#include <string>
3.#include <thread> //线程
4.using namespace std;
5.
6.//创建的线程,也就是一个初始函数
7.void myprint(){
8.    cout<<"1 begin" <<endl;
9.    cout<<"2 end"<<endl;
10.}
11.
12.int main(){
13.    thread myobj(myprint);//创建线程,线程就已经开始执行了
14.    myobj.join();//阻塞主线程,让主线程等子线程执行完,然后主线程继续往下走
15.    //如果不写join,可能main先执行完了,子线程还没执行完,会报错
16.    cout<<"main end"<<endl;
17.    return 0;
18.}

2、detach

一般情况主线程要等子线程都执行完在继续,也有例外。

detach函数:分离,主线程不用等子线程了,主线程你执行你的,子线程我执行我的,不汇合了。(一般不用detach)

原因:创建了很多子线程,让主线程逐个等待子线程结束不太好,就提出了detach。

一点detach只有,这个thread对象就失去了与主线程的联系,这些子线程就会驻留在后台运行,由c++运行时库接管,子线程结束后,运行时库负责清理线程相关的资源(守护线程)。

 1 1.#include <iostream>  
 2 2.#include <thread> //线程  
 3 3.using namespace std;  
 4 4.  
 5 5.//创建的线程,也就是一个初始函数  
 6 6.void myprint(){  
 7 7.    cout<<"1 begin" <<endl;  
 8 8.    cout<<"2 end"<<endl;  
 9 9.}  
10 10.  
11 11.int main(){  
12 12.    thread myobj(myprint);//创建线程,线程就已经开始执行了  
13 13.    myobj.detach();  
14 14.    cout<<"main end"<<endl;  
15 15.    return 0;  
16 16.}  

一旦用了detach,就不能再用join了。

3、joinable()

判断是否可以成功使用join或detach,返回true或false。

一般可以用在使用join或detach之前,用来提前先判断,如果true,就使用true或detach;否则就不能使用join或detach函数。

二、用类创建线程

用类对象创建线程,这个对象实际上是被复制到线程中的,执行完主线程后,这个类对象会被销毁,但是复制的这个对象依旧存在,直到这个子线程结束,只要你这个类对象里面没有引用、指针,就不会产生问题。

当类对象里面有引用时:

 1 #include <iostream>
 2 #include <thread> //线程
 3 using namespace std;
 4
 5 class TA{
 6 public:
 7     int &m_i;//引用
 8     TA(int &i):m_i(i){}//构造函数,引用i
 9     void operator()(){ //可以实现将对象当函数来使用
10         cout<<"m_i的值为"<<m_i<<endl;
11     }
12 };
13
14 int main(){
15     int a=9;
16     TA ta(a);//引用a
17     thread myobj(ta);//ta为可调对象,
18     myobj.detach();
19     //这个时候使用detach的话,有可能主线程先执行完,那么a被销毁,由于TA是引用,也就是指向了一个已经销毁的内存,会出错的,只能用join
20     cout<<"main end"<<endl;
21     return 0;
22 }

如果主线程先执行完,那么a被销毁,TA的成员变量是引用类型的,也就是子线程使用的是一个指向(引用是特殊的指针)了一个已经回收的地址,类似于野指针,就会出错,所以不要用detach。

改成join后,分析代码:创建ta对象:

  1. 创建类对象ta,构造函数被执行;
  2. 创建线程myobj,里面的ta对象复制给线程myobj,复制的ta对象构造函数执行;
  3. 执行线程,主线程等待子线程结束;
  4. 子线程myobj结束,复制的ta对象执行析构函数;
  5. 主线程继续执行 main end;
  6. main函数代码跑完了,主线程执行完毕,ta对象析构函数执行,释放内存和变量a;

三、用lambda表达式

 1 #include <iostream>
 2 #include <thread> //线程
 3 using namespace std;
 4
 5 int main(){
 6     auto mythread = []{
 7         cout<<"我的子线程开始了"<<endl;
 8         cout<< "结束了"<<endl;
 9     };
10     thread myobj(mythread);
11     myobj.join();
12     cout<<"main end"<<endl;
13     return 0;
14 }

TA构造函数执行,创建线程myobj,这个ta对象时复制进去的,所以这个

原文地址:https://www.cnblogs.com/pacino12134/p/11227877.html

时间: 2024-10-28 21:05:32

二、线程创建、结束的相关文章

爪哇国新游记之十二----线程创建的两种形式

public class Thread1 extends Thread{ public void run(){ int i=0; while(i<10){ i++; System.out.println(i); } } public static void main(String[] args){ Thread1 t=new Thread1(); t.start(); } } public class Thread2 implements Runnable{ @Override public v

iOS开发——多线程OC篇&amp;(二)线程创建

创建线程 一.创建和启动线程简单说明 一个NSThread对象就代表一条线程 创建.启动线程 (1) NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; [thread start]; // 线程一启动,就会在线程thread中执行self的run方法 主线程相关用法 + (NSThread *)mainThread; // 获得主线程 - (BOOL)isMa

win32多线程 (一) 线程创建与结束等待

#include "stdafx.h"#include <Windows.h>#include <iostream> using namespace std; DWORD WINAPI ThreadFuncFirst(LPVOID param){ int iCount = 50; while(iCount--){  cout<<"\nThreadFuncFirst:"<<iCount; } return 0;} DWO

线程的基本操作,创建线程,结束线程,新线程跟原线程共享变量

#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <pthread.h> // 包含线程库 #include <string.h> void *thread_function(void *arg); // 定义线程函数原型 //char message[] = "THREAD_TEST"; // 定义公用的内存空间 char message[

JAVA并发编程-线程创建(二)

对于线程的创建及更加详细的信息可以参看博客<JAVA--线程>,下面是对线程创建的细化及简单再实现. 在java中如果要创建线程的话,一般有两种方式:1)继承Thread类:2)实现Runnable接口. 方式一:继承Thread类 MyThread: package com.tgb.hjy; public class MyThread extends Thread{ private String name; public MyThread(String name){ this.name=na

Java并发编程(二)-- 创建、运行线程

Java线程 Java线程类也是一个object类,它的实例都继承自java.lang.Thread或其子类. Java可以用如下方式创建一个线程: Tread thread = new Thread(); 执行该线程可以调用该线程的start()方法: thread.start(); 在上面的例子中,我们并没有为线程编写运行代码,因此调用该方法后线程就终止了. 创建.执行线程的方式 无返回: 实现Runnable接口; 继承Thread类,重写run(); 有返回: 实现Callable接口,

并发编程专题(二)-线程的创建方式

1.创建多线程几种方式 1.1 继承Thread,重写父类的run()方法 Java使用java.lang.Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例.每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码.Java使用线程执行体来代表这段程序流.Java中通过继承Thread类来创建并启动多线程的步骤如下: 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程

java_10:线程创建的方式二

除了继承Thread类和实现Runnable接口两种创建线程的方式,JDK5.0还新增类两种线程创建方式: 新增方式一:实现Callable接口 好处:(1)与使用Runnable相比,Callable功能更强大些(2)相比run()方法,可以有返回值(3)方法可以抛出异常(4)支持泛型的返回值(5)需要借助FutureTask类,比如获取返回结果Future接口:1)可以对具体的Runnable\Callable任务的执行结果进行取消.查询是否完成.获取结果等2)FutureTask是Futu

Java基础系列之(二) - 线程

一.线程的实现方式 1.继承Thread 2.实现Runnable接口 二.线程的状态 1.New(新生线程) 当你new一个Thread,newThread(r),这时处于线程的新生状态,此时程序还没有真正的运行. 2.Runnable(可运行的) 当启动start()方法时,此时线程处于可运行状态,不一定运行之中,这取决与线程是否得到CPU的运行时间片.事实上,一个线程并不是一直处于运行状态,偶尔需要被中断,让其他线程有运行的机会. 3.Blocked(被阻塞) 当发生以下情况被阻塞 -线程