#include
#include
std::thread t(func); //无参数函数
std::thread t(func, parameter) //带参数函数
std::thread t(&class::func, this, parameter) //类内函数新起线程 第一个参数类函数指针,第二个参数对象指针
//如果要参数要被改变。采用std::ref
t.joinable();
t.join();
t.detach();
//创建线程后,可选用join和detach
//joinable:join或detach一次,多次返回false
//detach方式,启动的线程自主在后台运行,当前的代码继续往下执行,不等待新线程结束。detach将线程与主线程剥离,不再受主线程管理。
//注意:在释放各个对象时,请确保detach的线程已完成
//join方式,等待启动的线程完成,才会继续往下执行。join的意思为进入到线程里
//注意:线程的启动与否与join和detach无关,创建线程后,线程已经启动开始运行
std::thread t3(move(t1)); //将线程从t1转移给t3
t1.swap(t2); //交换线程
std::this_thread::sleep_for(chrono::milliseconds(10)); //线程等待
t.get_id(); //获取线程id
auto mainThreadId = std::this_thread::get_id(); //在当前线程获取id
//std::mutext: 独占的互斥量,不能递归使用
//std::timed_mutex: 带超时的互斥量,不能递归使用。try_lock_for
//std::recursive_mutex: 递归互斥量,不带超时功能。
//std::recursive_timed_mutex: 带超时的递归互斥量
std::mutex g_lock;
g_lock.lock(); //锁
g_lock.unlock(); //去锁
//互斥锁:
//lock() :第一个线程进去后,后面的线程会进入阻塞休眠状态,被放入到阻塞队列中。
//unlock():加锁的线程执行完后,会解锁,然后去阻塞队列中唤醒阻塞线程
//适用于锁的粒度大的场景
//自旋锁:
//lock():第一个线程进去,后面的线程在循环空转检查。
//unlock():第一个加锁的线程解锁,后面的线程检测到就可以被cpu调度。
std::lock_guard<std::mutex> lock(mutex); //获取互斥量,创建时,自动锁, 析构时,自动释放
std::unique_lock<std::mutex> lock(mutex, std::defer_lock); //比lock_guard功能更强,也具有自动创建锁的功能,但若指定为defer_lock,则不自动创建锁
std::recursive_mutex mutex;
std::lock_guard<std::recursive_mutex> lock(mutex); // 获取互斥量
t1.native_handle(); //返回 native handle(由于 std::thread 的实现和操作系统相关,因此该函数返回与 std::thread 具体实现相关的线程句柄,
t1.hardware_concurrency(); // 检测硬件并发特性,返回当前平台的线程实现所支持的线程并发数目,但返回值仅仅只作为系统提示(hint)
std::this_thread::yield(); //当前线程放弃执行,操作系统调度另一线程继续执行。
sleep_until();// 线程休眠至某个指定的时刻(time point),该线程才被重新唤醒。
#include
// 定义线程的 id 变量,多个变量使用数组
std::pthread_t tids[NUM_THREADS];
std::pthread_create(thread, attr, start_routine, arg);
int ret = pthread_create(&tids[i], NULL, say_hello, NULL);
//参数依次是:创建的线程id,线程参数,调用的函数,传入的函数参数
//thread 指向线程标识符指针。
//attr 一个不透明的属性对象,可以被用来设置线程属性。您可以指定线程属性对象,也可以使用默认值 NULL。
//start_routine 线程运行函数起始地址,一旦线程被创建就会执行。
//arg 运行函数的参数。它必须通过把引用作为指针强制转换为 void 类型进行传递。如果没有传递参数,则使用 NULL。
std::pthread_exit(NULL); //终止线程
std::pthread_join(threadid, status) //连接线程,子程序阻碍调用程序,直到指定的 threadid 线程终止为止。
std::pthread_detach(threadid); //分离线程
std::pthread_attr_t attr; //定义线程属性
// 初始化并设置线程为可连接的(joinable)
std::pthread_attr_init(&attr);
std::pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
// 删除属性
std::pthread_attr_destroy(&attr);
1)线程创建时,就已开始运行。
2)detach分离线程,后台运行,主线程不再对该线程有控制权限,
3)join,跳转进入到子线程当中,线程会阻塞到当前,线程运行结束才会继续执行主线程后续的程序
#include
#include
#include
void func(int* count){
*count = 0;
while(1){
std::this_thread::sleep_for(std::chrono::seconds(1));
*count += 1;
std::cout << "count = " << *count << std::endl;
if (*count > 10) break;
}
}
int main(){
int* count = new int[1];
std::thread* t_a = new std::thread();
std::thread t(func, std::ref(count));
std::cout << "t_a.id = " << t_a->get_id() << std::endl;
std::cout << "t.id = " << t.get_id() << std::endl;
std::cout << "t_a.native_handle = " << t_a->native_handle() << std::endl;
std::cout << "t.native_handle = " << t.native_handle() << std::endl;
t_a->swap(t); //交换两个线程
if(t_a->joinable()) t_a->join();
std::cout << "t_a.id = " << t_a->get_id() << std::endl;
std::cout << "t.id = " << t.get_id() << std::endl;
std::cout << "t_a.native_handle = " << t_a->native_handle() << std::endl;
std::cout << "t.native_handle = " << t.native_handle() << std::endl;
delete[] count;
return 0;
}
/*
t_a.id = thread::id of a non-executing thread
t.id = 2
t_a.native_handle = 0
t.native_handle = 2
count = 1
count = 2
count = 3
count = 4
count = 5
count = 6
count = 7
count = 8
count = 9
count = 10
count = 11
t_a.id = thread::id of a non-executing thread
t.id = thread::id of a non-executing thread
t_a.native_handle = 0
t.native_handle = 0
*/
分析:
join阻塞,执行完后才会执行之后的代码
new的线程没有句柄和相应的id
线程结束后,id都没有,但是句柄都不存在
#include
#include
#include
void func(int* count){
*count = 0;
while(1){
std::this_thread::sleep_for(std::chrono::seconds(1));
*count += 1;
std::cout << "count = " << *count << std::endl;
if (*count > 10) break;
}
}
int main(){
int* count = new int[1];
std::thread* t_a = new std::thread();
std::thread t(func, std::ref(count));
std::cout << "t_a.id = " << t_a->get_id() << std::endl;
std::cout << "t.id = " << t.get_id() << std::endl;
std::cout << "t_a.native_handle = " << t_a->native_handle() << std::endl;
std::cout << "t.native_handle = " << t.native_handle() << std::endl;
t_a->swap(t); //交换两个线程
if(t_a->joinable()) t_a->detach();
std::cout << "t_a.id = " << t_a->get_id() << std::endl;
std::cout << "t.id = " << t.get_id() << std::endl;
std::cout << "t_a.native_handle = " << t_a->native_handle() << std::endl;
std::cout << "t.native_handle = " << t.native_handle() << std::endl;
while(1){
std::this_thread::sleep_for(std::chrono::seconds(5));
break;
}
delete[] count;
return 0;
}
/*
t_a.id = thread::id of a non-executing thread
t.id = 2
t_a.native_handle = 0
t.native_handle = 2
t_a.id = thread::id of a non-executing thread
t.id = thread::id of a non-executing thread
t_a.native_handle = 0
t.native_handle = 0
count = 1
count = 2
count = 3
count = 4
*/
分析:
detach阻塞,线程分离,直接执行后续程序
需要注意:
1)程序本身并没有正常退出,而是删除了导致的异常退出。因此,detach需要注意子线程是否完成。
2)如果在线程结束前,delete了count,也会异常退出。
3)即使删除了t_a线程,也不能终止线程
//使用RAII等待线程完成
class thread_guard{
std::thread& t;
public:
explicit thread_guard(std::thread& t_): t(t_){}
~thread_guard()
{
if(t.joinable()){
t.join();
}
}
thread_guard(thread_guard const&)=delete;
thread_guard& operate=(thread_guard const&)=delete;
};
struct func;
void f()
{
int some_local_state = 0;
func my_func(some_local_state);
std::thread t(my_func);
thread_guard g(t);
}
终止的方式分为:
现有的线程结束函数,包括linux系统的pthread.h
中的pthread_exit()
和pthread_cancel()
,windows系统的win32.h
中的ExitThread()
和TerminateThread()
,也就是说,C++没有提供kill掉某个线程的能力,只能被动地等待某个线程的自然结束,析构函数~thread()
也不能停止线程,析构函数只能在线程静止时终止线程joinable
,对于连接/分离的线程,析构函数根本无法终止线程。
linux可以使用pthread_cancel的方式来结束线程,windows使用TerminateThread结束没有成功,而ExitThread需要在线程内执行,才能结束线程
#include
#include
#include
#include
#include
#include
#include
class Foo {
public:
void sleep_for(const std::string &tname, int num)
{
int count = 0;
while(1){
std::this_thread::sleep_for(std::chrono::seconds(1));
count += 1;
std::cout << tname + " count = " << count << std::endl;
if (count > num) break;
}
}
void start_thread(const std::string &tname)
{
std::thread thrd = std::thread(&Foo::sleep_for, this, tname, 5);
tm_[tname] = thrd.native_handle();
thrd.detach();
std::cout << "Thread " << tname << " created:" << std::endl;
}
void stop_thread(const std::string &tname)
{
ThreadMap::const_iterator it = tm_.find(tname);
if (it != tm_.end()) {
pthread_cancel(it->second);
tm_.erase(tname);
std::cout << "Thread " << tname << " killed:" << std::endl;
}
}
private:
typedef std::unordered_map<std::string, pthread_t> ThreadMap;
ThreadMap tm_;
};
int main()
{
Foo foo;
std::string keyword("test_thread");
std::string tname1 = keyword + "1";
std::string tname2 = keyword + "2";
foo.start_thread(tname1);
foo.start_thread(tname2);
while(1){
std::this_thread::sleep_for(std::chrono::seconds(2));
break;
}
foo.stop_thread(tname1);
foo.stop_thread(tname2);
std::cout << "has no exception" << std::endl;
return 0;
}
/*
Thread test_thread1 created:
Thread test_thread2 created:
test_thread1 count = 1
test_thread2 count = 1
test_thread2 count = 2
test_thread1 count = 2
Thread test_thread1 killed:
Thread test_thread2 killed:
has no exception
*/
线程运行一段时间后,被取消。
std::shared_ptr<int> p(new int(1));
std::shared_ptr<int> p2 = p; //p和p2共享同一段内存, 如果p2申请了空间,也会释放p2,p的次数加1
std::shared_ptr<int> ptr;
ptr.reset(new int(1));
int *p1 = new int[2];
std::shared_ptr<int> p3(p1); //p1和p3共享同一段内存
//使用make_shared. 更高效
auto p1 = std::make_shared<int>(10);
auto p2 = std::make_shared<string>(10,"s");
auto p3 = std::make_shared<Struct>();
std::shared_ptr<int> ptr(new int(1)); //方式1
std::shared_ptr<int> ptr = std::make_shared<int>() //方式2
//方式1:std::shared_ptr构造函数会执行两次内存申请,两次空间申请均在堆上,且不连续。
//而方式2:std::make_shared则执行一次,申请一次空间。只申请一次,堆空间连续。
std::shared_ptr<int> ptr(new int(1));
int *p = ptr.get();
void deleteIntPtr(int* p)
{
delete p;
}
std::shared_ptr<int> p5(new int,deleteIntPtr);
//使用lambda表达式
std::shared_ptr<int> p6(new int,[](int* p){delete p;});
std::shared_ptr<int> p6(new int[10],[](int* p){delete[] p;}); //数组
std::shared_ptr<int> p7(new int[10],std::default_delete<int[]>); //使用default_delete作为删除器
//封装,使得共享指针支持共享数组
template<typename T>
std::shared_ptr<T> make_shared_array(size_t size)
{
return std::shared_ptr<T>(new T[size],std::default_delete<T[]>());
}
std::shared_ptr<int> p8 = make_shared_array<int>(10);
std::shared_ptr<char> p9 = make_shared_array<char>(10);
int* p11 = new int;
std::shared_ptr<int> p12(p11);
std::shared_ptr<int> p13(p11);
deleteIntPtr(std::shared_ptr<int>(new int));//错误的
std::shared_ptr<int> p14(new int());
deleteIntPtr(p14);//OK
struct A
{
std::shared_ptr<A> getSelf()
{
return std::shared_ptr<A>(this); //错误,
}
};
int main()
{
std::shared_ptr<A> sp1(new A);
std::shared_ptr<A> sp2 = sp1->getSelf();//会导致重复析构
return 0;
}
// 正确使用方式
class A:public std::enable_shared_from_this
{
public:
std::shared_ptr<A> getSelf()
{
return shared_from_this();
}
};
struct A;
struct B;
struct A
{
std::shared_ptr<B> bptr;
~A(){cout << "A is deleted!"<<endl;}
};
struct B
{
std::shared_ptr<A> aptr;
~B() {cout << "B is deleted!"<<endl;}
};
int main()
{
{
std::shared_ptr<A> ap(new A);
std::shared_ptr<B> bp(new B);
ap->bptr = bp;
bp->aptr = ap;
}
}
sp.use_count()返回对象sp的引用计数。
shared_ptr<int> sp; //空智能指针
shared_ptr<int> sp2 = make_shared<int>(3);
shared_ptr<int> sp3(sp2);
cout << sp.use_count() << endl; //输出0
cout << sp2.use_count() << endl; //输出2
拷贝一个shared_ptr,其所指对象的引用计数会递增加
多个局部shared_ptr指向该对象,那么函数结束时对象的引用计数就不应该只减1。例如:
shared_ptr<int> init()
{
shared_ptr<int> sp2 = make_shared<int>(3);
shared_ptr<int> sp3(sp2);
cout << sp2.use_count() << endl; //输出2
return sp2; //返回sp2,故引用计数递增,变为3(返回的copy的一个shared_ptr指针,sp2和sp3都会被销毁)
} //sp2和sp3离开作用域,引用计数减2,变为1
int main()
{
auto p = init(); //此处赋值的拷贝与return处的拷贝是一致的
cout << p.use_count() << endl; //输出1
return 0;
}
不影响计数与生命周期
//default consstructor
weak_ptr<string> wp;
{
shared_ptr<string> p = make_shared<string>("hello world!\n");
//weak_ptr对象也绑定到shared_ptr所指向的对象。
wp = p;
cout << "use_count: " <<wp.use_count() << endl;
}
//wp是弱类型的智能指针,不影响所指向对象的生命周期,
//这里p已经析构,其所指的对象也析构了,因此输出是0
cout << "use_count: " << wp.use_count() << endl;
use_count: 1
use_count: 0
例子:
void test_valid(weak_ptr<string> &wp)
{
if(shared_ptr<string> smptr2 = wp.lock())
{
cout << "the shared_ptr is valid\n";
}
else
{
cout << "the shared_ptr is not valid\n";
}
//检查被引用的对象是否已删除 false 仍存在 true 释放
if(!wp.expired())
{
//it is getting valid shared_ptr obj now;
shared_ptr<string> smptr1 = wp.lock();
cout << " get obj value: " << *smptr1;
}
}
int main()
{
shared_ptr<string> p = make_shared<string>("hello world!\n");
//default consstructor
weak_ptr<string> wp1;
//copy constructor
weak_ptr<string> wp2(p);
//assign constructor
weak_ptr<string> wp3 = wp2;
test_valid(wp2);
//释放被管理对象的所有权, 调用后 *this 不管理对象
wp2.reset();
test_valid(wp2);
return 0;
}
class Parent
{
public:
shared_ptr<Child> child;
};
class Child
{
public:
shared_ptr<Parent> parent;
};
shared_ptr<Parent> pA(new Parent);
shared_ptr<Child> pB(new Child);
pA->child = pB;
pB->parent = pA;
include <iostream>
#include
using namespace std;
void Check(weak_ptr<int> &wp)
{
shared_ptr<int> sp = wp.lock(); // 重新获得shared_ptr对象
if (sp != nullptr)
{
cout << "The value is " << *sp << endl;
}
else
{
cout << "Pointer is invalid." << endl;
}
}
int main()
{
shared_ptr<int> sp1(new int(10));
shared_ptr<int> sp2 = sp1;
weak_ptr<int> wp = sp1; // 指向sp1所指向的内存
cout << *sp1 << endl;
cout << *sp2 << endl;
Check(wp);
sp1.reset();
cout << *sp2 << endl;
Check(wp);
sp2.reset();
Check(wp);
system("pause");
return 0;
}
//创建一个空的unique_ptr的对象
std::unique_ptr<int> ptr1;
//检查unique_ptr是否为空
// 方法1
if(!ptr1)
std::cout<<"ptr1 is empty"<<std::endl;
// 方法2
if(ptr1 == nullptr)
std::cout<<"ptr1 is empty"<<std::endl;
//使用原始指针创建unique_ptr
std::unique_ptr<Task> taskPtr(new Task(22));
//使用make_unique创建
std::unique_ptr<Task> taskPtr = std::make_unique<Task>(34);
//获取被管理对象的指针
Task *p1 = taskPtr.get();
//重置,它将释放delete关联的原始指针并使unique_ptr 对象为空。
taskPtr.reset();
//unique_ptr不能复制
// 编译错误 : unique_ptr 不能复制
std::unique_ptr<Task> taskPtr3 = taskPtr2; // Compile error
// 编译错误 : unique_ptr 不能复制
taskPtr = taskPtr2; //compile error
//转移 unique_ptr 对象的所有权,转移后,taskPtr2为空
std::unique_ptr<Task> taskPtr4 = std::move(taskPtr2);
//释放原始指针所有权,返回原始指针。释放所有权,并没有delete原始指针,reset()会delete原始指针。
Task * ptr = taskPtr5.release();