浅谈-线程

线程管理

1. 启动线程

启动一个简单的线程

范例 1

使用普通函数

#include <thread>

#include <iostream>

void do_task()

{

std::cout << "task thread id:" << std::this_thread::get_id() << std::endl;

}

int main()

{

//创建一个线程

std::thread t = std::thread(do_task);

//堵塞主线程,等待子线程执行完毕

t.join();

std::cout << "main thread id:" << std::this_thread::get_id() << std::endl;

return 0;

}

范例 2

使用lambda

#include <thread>

#include <iostream>

int main()

{

for (int i = 0; i < 20; ++i) {

std::thread t = std::thread([i](){

std::cout << "thread " << i << " id:" << std::this_thread::get_id() << std::endl;

});

t.join();

}

std::cout << "main thread id:" << std::this_thread::get_id() << std::endl;

return 0;

}

范例 3

仿函数(重载运算符)

#include <thread>

#include <iostream>

class Task

{

public:

//重载()操作符

void operator()(int i)

{

std::cout << "task thread " << i << "id:" << std::this_thread::get_id() << std::endl;

}

};

int main()

{

Task task;

//创建线程,并且传递参数

std::thread t = std::thread(task, 10);

//堵塞主线程,等待子线程完成

t.join();

std::cout << "main thread id:" << std::this_thread::get_id() << std::endl;

return 0;

}

2.向线程传递参数

默认的方式是使用拷贝的方式,复制到线程空间,即使参数的类型是引用

使用指针传递参数

#include <thread>

#include <stdio.h>

void task(const char* pBuffer, int n)

{

fprintf(stdout, "buffer: %s, %d", pBuffer, n);

}

int main()

{

char* buffer = NULL;

int n = 10;

//申请12字节的内存

buffer = (char*)malloc(sizeof(char) * 12);

//拷贝到数据到buffer

strcpy(buffer, "hello thread");

//传递的参数, 不能是右值的零时变量

std::thread t = std::thread(task, buffer, n);

t.join();

return 0;

}

使用std::ref

#include <thread>

#include <iostream>

#include <string>

class ObjectClass

{

public:

ObjectClass(std::string& data)

:m_data(data)

{}

public:

std::string& m_data;

};

void func(ObjectClass& object)

{

std::cout << "objectName:" << object.m_data << std::endl;

}

int main()

{

std::string tag = "object";

ObjectClass object(tag);

//创建线程, 使用std::ref传递引用的对象

std::thread t = std::thread(func, std::ref(object));

//堵塞线程,等待子线程执行完毕

t.join();

return 0;

}

使用类中的方法

#include <thread>

#include <iostream>

#include <string>

class ObjectClass

{

public:

explicit ObjectClass(std::string& tag)

:m_tag(tag)

{}

void func(int n)

{

std::cout << "tag:" << this->m_tag << ", n:" << n << std::endl;

}

private:

std::string& m_tag;

};

int main()

{

std::string tag = "object";

ObjectClass object(tag);

//使用类方法,放到子线程中使用;

std::thread t = std::thread(&ObjectClass::func, &object, 10);

//堵塞线程,等待子线程执行完毕

t.join();

return 0;

}

3.线程权限转移

thread 是可移动(movable), 但是不可复制的(copyable)

#include <thread>

#include <iostream>

void do_task()

{

std::cout << "task thread id:" << std::this_thread::get_id() << std::endl;

}

int main()

{

//创建一个线程

std::thread t = std::thread(do_task);

//线程t的权限移动到t2后,t变得不确定,

std::thread t2 = std::thread(std::move(t));

t2.join();

std::cout << "main thread id:" << std::this_thread::get_id() << std::endl;

return 0;

}

4.异常的线程处理

局部变量

局部变量引用的误区

#include <thread>

#include <iostream>

void task(int* pInt)

{

std::cout << "int value:" << *pInt << std::endl;

}

int main()

{

int i = 10;

//创建线程

std::thread t = std::thread(task, &i);

//分离子线程

t.detach();

//主线程执行完毕,i变量资源回收,i的值变的不确定

return 0;

}

主线程异常

当主线程发生异常时,如何保证子线程正确被回收

范例1

子线程不分离

#include <thread>

#include <iostream>

#include <exception>

void task()

{

std::cout << "task thread id:" << std::this_thread::get_id() << std::endl;

}

void do_something()

{

throw std::runtime_error("has exception");

}

int main()

{

std::thread t(task);

try {

//主线程在执行过程中,发生异常,为了正确处理,线程等待,需要加入异常处理

do_something();

} catch (std::exception & e)

{

//等待子线程完成

t.join();

throw e;

}

//等待子线程完成

t.join();

return 0;

}

范例 2

子线程分离

#include <thread>

#include <iostream>

#include <exception>

void task()

{

std::cout << "task thread id:" << std::this_thread::get_id() << std::endl;

}

void do_something()

{

throw std::runtime_error("has exception");

}

int main()

{

//创建线程

std::thread t = std::thread(task);

//线程分离,为了防止在创建线程后发生异常,导致线程无法回收

t.detach();

do_something();

return 0;

}

范例 3

使用资源管理类

#include <thread>

#include <iostream>

#include <exception>

class ThreadGuard

{

public:

//构造函数

explicit ThreadGuard(std::thread&t)

:t(t){}

//析构函数

~ThreadGuard()

{

//析构函数时,顺道堵塞主线程,等待子线程执行完毕,这就是资源回收

if(t.joinable())

{

t.join();

}

}

private:

std::thread &t;

};

void task()

{

std::cout << "task thread id:" << std::this_thread::get_id() << std::endl;

}

void func()

{

std::thread t = std::thread(task);

ThreadGuard guard(t);

//超出作用域后,自动回收资源

}

void do_task()

{

throw std::runtime_error("exception");

}

int main()

{

func();

do_task();

return 0;

}


分享到:


相關文章: