文章目录
九、多线程
3. C++11中的多线程
Linux中是根据多线程库来实现多线程的,C++11也有自己的多线程,那它的多线程又是怎样的?我们来使用一些C++11的多线程。
Makefile:
testThread: testThread.cc
g++ -o $@ $^ -std=c++11
.PHONY: clean
clean:
rm -f testThread
testThread.cc
#include <iostream>
#include <thread>
#include <unistd.h>
using namespace std;
void threadrun(int num)
{
while (num)
{
cout << "I am thread, num : " << num << endl;
sleep(1);
--num;
}
}
int main()
{
thread t1(threadrun, 10);
while (true)
{
cout << "I am main thread" << endl;
sleep(1);
}
t1.join();
return 0;
}
编译看看:
我们发现有问题(也可能是其他问题),这是怎么回事呢?其实是 C++11的多线程本质上是对原生线程的封装。所以同样需要链接 phread 动态库。
Makefile:
testThread: testThread.cc
g++ -o $@ $^ -std=c++11 -lpthread
.PHONY: clean
clean:
rm -f testThread
我们再试试:
确实大部分其编程语言的多线程都是对原生线程的封装,原因是为了可移植性。
我们在进程部分学过 非阻塞等待 ,进程在等待子进程退出时,可以执行其他任务,在线程这里,同样有这样的技术,叫做线程分离。我们要是不关注线程的结果,只需要线程把自己的任务完成,这种情况就可以将线程进行分离。
Makefile:
testThread: testThread.cc
g++ -o $@ $^ -std=c++11 -lpthread
.PHONY: clean
clean:
rm -f testThread
testThread.cc:
#include <iostream>
#include <pthread.h>
#include <string>
#include <unistd.h>
using namespace std;
void* threadrun(void* args)
{
string str = (const char*)args;
int cnt = 5;
while (true)
{
if (!(cnt--)) break;
cout << "I am a new thread " << endl;
sleep(1);
}
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, threadrun, (void*)"thread1");
// 线程分离
pthread_detach(tid);
while (true)
{
cout << "I am the main thread " << endl;
sleep(1);
}
return 0;
}
默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏。
如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。
joinable和分离是冲突的,一个线程不能既是joinable又是分离的。如果将线程分离了又对其join,就会出错。
线程分离底层依旧是属于进程,没有分开,线程分离只是一种状态,唯一的区别就是主线程不需要等待新线程。
4. 线程的简单封装
Makefile:
testThread: testThread.cc
g++ -o $@ $^ -std=c++11 -lpthread
.PHONY: clean
clean:
rm -f testThread
Thread.hpp:
#ifndef __THREAD_HPP__
#define __THREAD_HPP__
#include <iostream>
#include <pthread.h>
#include <string>
#include <functional>
#include <unistd.h>
// 线程命名空间
namespace ThreadModule
{
// 线程函数模板
template<typename T>
using func_t = std::function<void(T&)>;
// 线程模板
template<typename T>
class Thread
{
public:
Thread(func_t<T> func, T data, const std::string& name = "none-name")
:_func(func)
,_data(data)
,_threadname(name)
,_stop(true)
{}
void Excute()
{
_func(_data);
}
static void* threadtoutine(void* args)
{
Thread<T>* self = (Thread<T>*)args;
self->Excute();
return nullptr;
}
// 启动线程
bool Start()
{
int n = pthread_create(&_tid, nullptr, threadtoutine, this);
if (n == 0)
{
_stop = false;
return true;
}
else return false;
}
// 分离线程
void Detach()
{
if (!_stop)
{
pthread_detach(_tid);
}
}
// 等待线程结束
void Join()
{
if (!_stop)
{
pthread_join(_tid, nullptr);
}
}
std::string name()
{
return _threadname;
}
// 停止线程
void Stop()
{
_stop = true;
}
~Thread(){}
private:
pthread_t _tid;
std::string _threadname;
T _data;
func_t<T> _func;
bool _stop;
};
}
#endif
testThread.cc:
#include <iostream>
#include <vector>
#include "Thread.hpp"
using namespace ThreadModule;
const int num = 10;
// 线程执行的任务
void print(int& cnt)
{
while (cnt)
{
std::cout << "hello I am myself thread, cnt: " << cnt-- << std::endl;
sleep(1);
}
}
int main()
{
// 创建多线程
std::vector<Thread<int>> threads;
// 创建num个线程,每个线程执行print函数
for (int i = 0; i < num; ++i)
{
std::string name = "thread-" + std::to_string(i + 1);
threads.emplace_back(print, 10, name);
}
// 启动线程
for (auto& thread : threads)
{
thread.Start();
}
// 等待线程结束
for (auto& thread : threads)
{
thread.Join();
std::cout << "wait thread done, thread name: " << thread.name() << std::endl;
}
return 0;
}
结果: