1. 线程的基本概念
1.1、线程与进程的区别
并行:两个或者多个进程或者线程在同一时刻运行(点)
并发:两个或者多个进程或者线程在同一时间段运行(线)高并发
单个CPU,时间片
进程:是资源分配的基本单位。
线程:是CPU调度和执行的基本单位。每个进程至少包含一个线程,也就是main线程。进程中的线程会共享线程的资源,共享线程的地址空间,包括:堆空间、代码段、文件描述符、信号等等。但是每个线程有属于自己独立的少量栈空间。
为什么需要类比?类比的学习方法
线程和进程在使用上各有优缺点: 线程执行开销小, 占用的 CPU 少, 线程之间的切换快, 但不利于资源的管理和保护。进程与线程是相反的。
1.2、线程的分类
用户态空间(0-3G):运行在用户态的线程称为用户级线程(用户态线程),可以调用系统调用
内核态空间(3G-4G):运行在内核态的线程称为内核级线程(内核态线程)
POSIX标准:可移植性。
1.3、线程的创建(最重要)
Compile and link with -pthread.
#include <pthread.h>
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine) (void *),
void *arg);
//thread:线程id,为了与其他线程做区分。
//attr:线程的属性,线程的特性,可以使用默认属性,将其设置空即可。
//start_routine:线程入口函数,线程需要去做的任务,都写在该函数中。start_routine是一个函数指针。
//arg:代表的是线程的参数。
//函数的返回类型是一个int,如果线程创建成功,就会返回0,如果线程创建失败,会返回错误码。
int number;
float fx;
const char *pstr = "hello";
typedef struct
{
int number;
float fx;
char *pstr;
}Data_t;
Data_t *p;
1.4、线程的退出
#include <pthread.h>
void pthread_exit(void *retval);
//retVal:线程退出时候的值(状态)
1.5、线程等待
等待的目的就是想让子线程执行完毕,然后可以回收子线程的资源。
int pthread_join(pthread_t thread, void **retval);
//thread:传递进来的是被等待线程的id
//retVal:将等待线程的状态值取出来
1.6、获取线程id
pthread_t pthread_self(void);
线程的执行是具有随机性的,因为时序不一样,所以每次运行的结果都有可能是不一样的。
1.7、线程的取消
int pthread_cancel(pthread_t thread);
//thread:被取消的线程id
1.8、线程的分离
如果想让主线程不去等待或者回收子线程,那么可以将子线程设置为分离状态。
int pthread_detach(pthread_t thread);
2. 线程封装
2.1 面向对象的线程封装
#ifndef __THREAD_H__
#define __THREAD_H__
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <iostream>
#include <memory>
using std::cout;
using std::endl;
#define ERROR_CHECK(msg, ret) \
do { \
printf("%s: %s", msg, strerror(ret));\
} while (0)
class Thread
{
public:
Thread();
virtual ~Thread();
// 线程创建和等待函数
void start();
void join();
// 线程执行函数
private:
static void * threadFunc(void *);
virtual void run() = 0;
private:
pthread_t _thid;
bool _isRunning;
};
#endif
// Thread.cc
#include "Thread.h"
Thread::Thread()
: _thid(0)
, _isRunning(false)
{
}
Thread::~Thread()
{
if (_isRunning)
{
pthread_detach(_thid);
_isRunning = false;
}
}
void Thread::start()
{
int ret = pthread_create(&_thid, nullptr, threadFunc, this);
if (ret)
{
perror("pthread_create");
return;
}
_isRunning = true;
}
void Thread::join()
{
int ret = pthread_join(_thid, nullptr);
if (ret)
{
perror("pthread_join");
return;
}
_isRunning = false;
}
void * Thread::threadFunc(void *args)
{
Thread *pth1 = (Thread *)args;
if (pth1)
pth1->run();
pthread_exit(nullptr);
}
// testThread.cc
#include "Thread.h"
class MyThread
: public Thread
{
public:
void run()
{
/* while (1) */
/* { */
sleep(1);
cout << "I am child thread." << endl;
/* } */
}
};
int main(int argc, char **argv)
{
/* MyThread mt; */
/* mt.start(); */
/* mt.join(); */
std::unique_ptr<Thread> pth(new MyThread());
pth->start();
pth->join();
return 0;
}
2.2 基于对象的线程封装
#ifndef __THREAD_H__
#define __THREAD_H__
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <iostream>
#include <memory>
#include <functional>
using std::cout;
using std::endl;
using std::function;
using std::bind;
#define ERROR_CHECK(msg, ret) \
do { \
printf("%s: %s", msg, strerror(ret));\
} while (0)
class Thread
{
using ThreadCallback = function<void()>;
public:
Thread(ThreadCallback &&);
virtual ~Thread();
// 线程创建和等待函数
void start();
void join();
// 线程执行函数
private:
static void * threadFunc(void *);
private:
pthread_t _thid;
bool _isRunning;
ThreadCallback _cb;
};
#endif
// Thread.cc
#include "Thread.h"
Thread::Thread(ThreadCallback &&cb)
: _thid(0)
, _isRunning(false)
, _cb(std::move(cb))
{
}
Thread::~Thread()
{
if (_isRunning)
{
pthread_detach(_thid);
_isRunning = false;
}
}
void Thread::start()
{
int ret = pthread_create(&_thid, nullptr, threadFunc, this);
if (ret)
{
perror("pthread_create");
return;
}
_isRunning = true;
}
void Thread::join()
{
int ret = pthread_join(_thid, nullptr);
if (ret)
{
perror("pthread_join");
return;
}
_isRunning = false;
}
void * Thread::threadFunc(void *args)
{
Thread *pth1 = (Thread *)args;
if (pth1)
pth1->_cb();
pthread_exit(nullptr);
}
// testThread.cc
#include "Thread.h"
class MyThread
{
public:
void run()
{
sleep(1);
cout << "I am child thread" << endl;
}
};
void func()
{
cout << "I am func" << endl;
sleep(1);
}
void test()
{
/* Thread *pth = new Thread(bind(&MyThread::run, new MyThread())); */
MyThread task;
function<void()> f = std::bind(&MyThread::run, &task);
std::unique_ptr<Thread> pth(new Thread(std::move(f)));
pth->start();
pth->join();
}
void test2()
{
function<void()> f = std::bind(func);
std::unique_ptr<Thread> pth(new Thread(std::move(f)));
pth->start();
pth->join();
}
int main(int argc, char **argv)
{
test2();
}