淺談-線程

線程管理

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;

}


分享到:


相關文章: