Vue框架:Vue驾校-从项目学Vue-1
算法系列博客友链:神机百炼
线程的定义:
一个程序中的一个执行路线
线程和进程的区别:
线程共享进程的内容:

页表分级存储的必要性:
页表分级存储的示意图:

pthread_create():
#include
pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);
参数:
返回值:
实例代码:
#include
#include
#include
#include
#include
void *func(void *arg){
while(1){
printf("child thread running\n");
sleep(1);
}
}
int main(){
pthread_t tid;
int ret;
if((ret = pthread_create(&tid, NULL, func, NULL)) != 0){
perror("pthread_create error\n");
exit(ret);
}
while(1){
printf("main thread running\n");
sleep(1);
}
return 0;
}
#编译指令
gcc -o pthread_create pthread_create.c -lpthread

前文提及了两次线程ID:
pthread_t类型的线程ID存储位置:

线程终止:只终止线程而不终止进程
线程终止三大方法:
线程函数return终止自己。
对主线程不适用,主线程return相当于exit()
线程调用pthread_exit()终止自己
调用pthread_cancel()终止另一进程
return:
void *func(void *arg){
int *p = (int*)malloc(sizeof(int));
*p = 1;
return (void*)p;
}
参数:
实例代码:
#include
#include
#include
#include
#include
void *func(void *arg){
printf("child thread ready to return\n");
int *p = (int*)malloc(sizeof(int));
*p = 1;
return (void*)p;
}
int main(){
int ret = 0;
pthread_t tid;
if((ret = pthread_create()){
perror("pthread_create error");
return -1;
}
printf("main thread ready to return\n");
while(1);
return 0;
}

pthread_exit():
#include
void pthread_exit(void *value_ptr);
作用:终止调用该函数的线程
参数:
返回值:由于调用成功则线程结束,所以该函数无返回值
实例代码:
#include
#include
#include
#include
#include
void *func(void *arg){
printf("child thread ready to exit\n");
int *p = (int *)malloc(sizeof(int))
*p = 1;
pthread_exit((void*)p);
}
int main(){
int ret = 0;
pthread_t tid;
if((ret = pthread_create(&tid, NULL, func, NULL)) != 0){
perror("pthread_create error");
return -1;
}
printf("main thread ready to return\n");
while(1);
return 0;
}

pthread_cancel():
#include
int pthread_cancel(pthread_t thread);
作用:终止以参数为线程id的线程
参数:线程id
返回值:
实例代码:
#include
#include
#include
#include
#include
#include <>
void *func(){
while(1){
printf("child thread is running\n");
sleep(1);
}
return NULL;
}
int main(){
int ret = 0;
pthread_t tid;
if((ret = pthread_create(&tid, NULL, func, NULL)) != 0){
perror("pthread_create error");
return -1;
}
sleep(5);
pthread_cancel(tid);
return 0;
}

为什么需要线程等待?
pthread_join():
#include
int pthread_join(pthread_t thread, void **value_ptr);
作用:等待thread号线程结束
参数:
返回值:
线程等待的终止状态:
根据线程终止的条件不同,线程等待得到的终止状态不同
进程等待的时间线:

实例代码:
#include
#include
#include
#include
#include
#include
void *thread1(void *arg){
printf("thread1 return\n");
int *p = (int*)malloc(sizeof(int));
*p = 1;
return (void*)p;
}
void *thread2(void *arg){
printf("thread2 pthread_exit\n");
int *p = (int*) malloc(sizeof(int));
*p = 2;
pthread_exit((void*)p);
}
void *thread3(void *arg){
while(1){
printf("thread3 pthread_cancled\n");
sleep(1);
}
return NULL;
}
int main(){
pthread_t tid;
void* ret;
//thread1:return
pthread_create(&tid, NULL, thread1, NULL);
pthread_join(tid, &ret);
printf("thread1 return %d\n", *(int*)ret);
free(ret);
//thread2:pthread_exit
pthread_create(&tid, NULL, thread2, NULL);
pthread_join(tid, &ret);
printf("thread2 pthread_exit(%d)\n", *(int*)ret);
free(ret);
//thread3:pthread_cancel
pthread_create(&tid, NULL, thread3, NULL);
sleep(3);
pthread_cancel(tid);
pthread_join(tid, &ret);
if(ret == PTHREAD_CANCELED){
printf("thread pthread_canceled PTHREAD_CANCELED\n");
}else{
printf("thread isn't pthread_canceled\n");
}
return 0;
}

进程分离:
矛盾:线程一旦分离,则不可再等待该进程退出了
pthread_detach():
#include
int pthread_detach(pthread_t thread);
参数:
实例代码:
#include
#include
#include
#include
void *func(void *arg){ pthread_detach(pthread_self());
printf("%s\n", (char*)arg);
return NULL;
}
int main(){
int ret = 0;
pthread_t tid;
if((ret = pthread_create(&tid, NULL, func, "child thread detach...")) != 0){ perror("pthread_create error...");
return -1;
}
sleep(3); //确保线程分离
if(pthread_join(tid, NULL) == 0){
printf("pthread_join wait success\n");
}else{
printf("pthread_join wait failed\n");
}
return 0;
}

线程中的变量:
局部变量:
变量的地址空间在线程栈空间内,变量归属单个线程,其他线程无法获得该变量
共享变量:
多个进程都可以访问到的变量
互斥量mutex:
本质:为线程加的一把锁
作用:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
#include
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
加锁可能遇到的情况:
pthread_lock():
#include
int pthread_mutex_lock(pthread_mutex_t *mutex);
参数:要加锁的互斥量
返回值:
pthread_mutex_unlock():
#include
int pthread_mutex_unlock(pthread_mutex_t *mutex);
参数:要解锁的互斥量
返回值:
销毁动态分配所得的互斥量前确定:
pthread_mutex_destroy():
#include
int pthread_mutex_destroy(pthread_mutex_t *mutex);
#include
#include
#include
int ticket = 100;
pthread_mutex_t mutex;
void *func(void *arg){
char* id = (char*) arg;
while(1){
pthread_mutex_lock(&mutex);
if(ticket > 0){
usleep(1000);
printf("%s sells ticket:%d\n", id, ticket);
ticket--;
pthread_mutex_unlock(&mutex);
}else{
pthread_mutex_unlock(&mutex);
break;
}
}
}
int main(){
pthread_t t1, t2, t3, t4;
pthread_mutex_init(&mutex, NULL);
pthread_create(&t1, NULL, func, "thread 1");
pthread_create(&t2, NULL, func, "thread 2");
pthread_create(&t3, NULL, func, "thread 3");
pthread_create(&t4, NULL, func, "thread 4");
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
pthread_join(t4, NULL);
pthread_mutex_destory(&mutex);
}

共享变量mutex:
一经创建和初始化则内存中的mutex值为1

pthread_mutex_lock():
加锁含有两步操作和一步判断:
将该线程拥有的CPU内与锁有关的al寄存器内值置为0

CPU原子交换值操作:swap()/exchange()

判断共享变量mutex值是否为0,若为0则线程阻塞,若非0则线程进入执行临界区代码
锁阻塞:
当一个线程已经将互斥锁持有,此时另一线程尝试取地锁时,该线程也执行了pthread_mutex_lock()的三大步骤,且是否持有锁查看的是最后的判断步骤
pthread_mutex_unlock():

适用情况:
一个线程等待"条件变量的条件成立"而挂起;
另一个线程使"条件成立"。 为了防止竞争,
同步:保证数据安全前提下,让线程能够按照某种特定顺序访问临界资源,从而避免饥饿问题
竞争条件:由于时序问题导致程序异常
定义:在多线程程序中用来实现"等待 -> 唤醒"逻辑常用的方法。
搭配使用:pthread_mutex_t,即条件变量的使用总是和一个互斥锁结合在一起。
pthread_cond_init():
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
作用:初始化条件变量cond
参数:
pthread_cond_destroy():
int pthread_cond_destroy(pthread_cond_t *cond);
作用:销毁条件变量cond
参数:
pthread_cond_wait():
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
作用:暂时释放当前线程持有的锁后,将调用该函数的线程阻塞等待
参数:
pthread_cond_signal():
int pthread_cond_signal(pthread_cond_t *cond)
作用:通过修改条件变量cond值,使得一个线程摆脱阻塞
参数:
pthread_cond_broadcast():
int pthread_cond_broadcast(pthread_cond_t *cond);
作用:通过修改条件变量cond值,使得所有线程摆脱阻塞
参数:
#include
#include
#include
using namespace std;
pthread_mutex_t mutex;
pthread_cond_t cond;
void *run(void *arg){
pthread_detach(pthread_self());
while(1){
pthread_wait();
cout<<"thread "<<pthread_self()<<" 摆脱条件变量阻塞"<<endl;
sleep(1);
}
pthread_exit((void*)0);
}
int main(){
pthread_mutex_init(&mutex, nullptr);
pthread_cond_init(&cond, nullptr);
pthread_t t1, t2, t3;
pthread_create(&t1, nullptr, run, nullptr);
pthread_create(&t2 nullptr, run, nullptr);
pthread_create(&t3, nullptr, run, nullptr);
while(1){
getchar();
pthread_cond_signal(&cond);
}
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}


#include
#include
#include
#include
#include
#include
#define NUM 32
using namespace std;
template<typename T>
class BlockQueue{
private:
bool IsFUll(){
return q.size() == cap;
}
bool IsEmpty(){
return q.size() == 0;
}
public:
BlockQueue(int _cap = NUM){
cap = _cap;
pthread_mutex_init(&mutex, nullptr);
pthread_cond_init(&full, nullptr);
pthread_cond_init(&empty, nullptr);
}
void Push(const T& in){
pthread_mutex_lock(&mutex);
if(IsFUll()){
//队列满则阻塞等待
pthread_cond_wait(&full, &mutex);
}
q.push(in);
pthread_mutex_unlock(&mutex);
//生产后队列不为空,供消费者消费:
pthread_cond_signal(&empty);
}
void Pop(T& out){
pthread_mutex_lock(&mutex);
if(IsEmpty()){
//队列为空则阻塞等待
pthread_cond_wait(&empty, &mutex);
}
out = q.front();
q.pop();
pthread_mutex_unlock(&mutex);
//消费后队列不满,供生产者生产
pthread_cond_signal(&full);
}
~BlockQueue(){
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&full);
pthread_cond_destroy(&empty);
}
private:
std::queue<T> q; //临界资源
pthread_mutex_t mutex; //锁
pthread_cond_t full, empty;
int cap;
};
void *Producter(void *arg){
auto bq = (BlockQueue<int> *)arg;
while(1){
int data = rand()%100 + 1;
bq->Push(data);
sleep(1);
}
}
void *Consumer(void *arg){
auto bq = (BlockQueue<int> *)arg;
while(1){
int data = 0;
bq->Pop(data);
cout<<"consumer: "<<data<<endl;
sleep(1);
}
}
int main(){
BlockQueue<int> *bq = new BlockQueue<int>();
srand((unsigned long)time(NULL));
pthread_t p, c;
pthread_create(&p, nullptr, Consumer, bq);
pthread_create(&c, nullptr, Producter, bq);
pthread_join(p, nullptr);
pthread_join(c, nullptr);
return 0;
}

信号量的本质:
核心是一个计数器,描述临界资源中的资源数目
功能实现依赖mutex互斥锁
维护着一个阻塞队列,实现阻塞线程之间相对有序
本身即是一个临界资源:多个线程都可以看到和操作该资源
伪代码:
struct {
ptread_mutex_t mutex; //以锁维护原子性
int count; //核心计数器
task_struct *queue; //阻塞队列
};
P操作:
申请信号量
本质是计数器- -,是依赖锁实现的原子操作
当P操作申请不到资源时,一定是资源暂时为空
此时线程陷入阻塞,进入信号量自带的阻塞队列
当P操作申请到资源时,获得的是资源的使用权,而不是已经在使用资源
V操作:
问:自定义临界全局变量充当信号量是否可行?
答:
sem_init():
#include
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
sem_wait():
#include
int sem_wait(sem_t *sem);
作用:P操作,信号量值-1
sem_post():
#include
int sem_post(sem_t *sem);
作用:V操作,信号量值+1
sem_destory():
#include
int sem_destroy(sem_t *sem);
#include
#include
#include
#include
using namespace std;
class Sem{
private:
sem_t sem;
public:
Sem(int num = 1){
sem_init(&sem, 0, num);
}
void P(){
sem_wait(&sem);
}
void V(){
sem_post(&sem);
}
~Sem(){
sem_destroy(&sem);
}
};
Sem sem(1);
int ticket = 2000;
void *GetTickets(void *arg){
string id = (char *)arg;
sleep(1);
while(1){
sem.P();
if(ticket > 0){
usleep(10000);
cout<<id <<" take ticket:"<<ticket--<<endl;
sem.V();
}else{
sem.V();
break;
}
}
cout<<id<<" quit"<<endl;
pthread_exit((void*)0);
}
int main(){
pthread_t tid1, tid2, tid3;
pthread_create(&tid1, nullptr,GetTickets, "thread 1");
pthread_create(&tid2, nullptr, GetTickets, "thread 2");
pthread_create(&tid3, nullptr, GetTickets, "thread 3");
pthread_join(tid1, nullptr):
pthread_join(tid2, nullptr);
pthread_join(tid3, nullptr);
return 0;
}

在基于队列的生产者消费者模型中,我们发现:
环形队列生产消费原则:
以上两条原则都由信号量来维护
#include
#include
#include
#include
#include
#include
#define NUM 5
using namespace std;
template <typename T>
class RingQueue{
private:
int cap;
vector<T> q;
sem_t blank, data;
int p_pos, c_pos;
private:
void P(sem_t &sem){
sem_wait(&sem);
}
void V(sem_t &sem){
sem_post(&sem);
}
public:
RingQueue(int _cap = NUM){
cap = _cap;
q.resize(cap);
sem_init(&blank, 0, cap);
sem_init(&data, 0, 0);
p_pos = c_pos = 0;
}
void Push(const T& in){
P(blank);
q[p_pos++] = in;
V(data);
p_pos %= cap;
}
void Pop(T& out){
P(data);
out = q[c_pos++];
V(blank);
c_pos %= cap;
}
~RingQueue(){
sem_destroy(&blank);
sem_destroy(&data);
}
}
void *product(void *arg){
RingQueue<int> *rq = (RingQueue<int>*) arg;
pthread_detach(pthread_self());
while(1){
int x = rand()%100 + 1;
rq->Push(x);
cout<<"Productor <<< "<<x<<endl;
sleep(1);
}
}
void *consume(void *arg){
RingQueue<int> *rq =
(RingQueue<int>*) arg; pthread_detach(pthread_self());
while(1){
int x = 0;
rq->Pop(x);
cout<<"Consumer <<< "<<x<<endl;
sleep(1);
}
}
int main(){
srand((unsigned long) time(0));
RingQueue<int> *rq = new RingQueue<int>();
pthread_t p, c;
pthread_create(&p, nullptr, Product, rq);
pthread_create(&c, nullptr, Consume, rq);
return 0;
}

定义:线程池是一种线程使用模式,一个线程池维护着多个线程,等待着管理者分配可并发执行的任务。
线程池大小:可用线程数取决于:
优点:避免了在处理短时间任务时创建与销毁线程的代价。
应用场景:
时间短,线程多:
如Web服务器,单个任务体量小,但是任务数量多,任务完成时间紧
性能要求苛刻的应用:
要求服务器迅速响应客户端请求
突发性大量客户请求:
短时间内产生大量进程可能使内存到达极限

#pragma once
#include
#include
using namespace std;
typedef int (*handler_t)(int, int, char);
//template
class Task{
private:
int x;
int y;
char op;
//handler_t handler;
public:
Task(int _x, int _y, char _op){
x = _x;
y = _y;
op = _op;
}
void Run(){
int z = 0;
switch(op){
case '+':
z = x+y;
break;
case '-':
z = z-y;
break;
case '*':
z = x*y;
break;
case '/':
if(y==0) cerr<<"div zero"<<endl;
else z = x/y;
break;
case '%':
if(y==0) cerr<<"mod zero"<<endl;
else z = x%y;
break;
default:
cerr<<"op error"<<endl;
break;
}
cout<<"thread [ "<<pthread_self()<<" ]:"<<x<<op<<y<<endl;
}
~Task(){
}
}
#pragma once
#include
#include "Task.hpp"
#define N 3
template <typename T>
class ThreadPool{
private:
queue<Task> task_queue;
int thread_num;
pthread_cond_t cond;
pthread_mutex_t mutex;
private:
void LockQueue(){
pthread_mutex_lock(&mutex);
}
void UnlockQueue(){
pthread_mutex_unlock(&mutex);
}
void Wait(){
pthread_cond_wait(&cond, &mutex);
}
void Wakeup(){
pthread_cond_signal(&cond);
}
void IsEmpty(){
return task_queue.size()==0;
}
public:
ThreadPool(int num=N){
thread_num = num;
pthread_mutex_init(&mutex, nullptr);
pthread_cond_init(&cond, nullptr);
}
void InitThreadPool(){
pthread_t tid;
for(int i=0; i<thread_num; i++)
pthread_create(&tid, nullptr, func, this);
}
}
void Push(const T& in){
LockQueue();
task_queue.push(in);
//取和放都加锁
UnlockQueue();
Wakeup();
}
void Pop(T &out){
out = task_queue.front();
task_queue.pop();
}
static void* func(void *arg){
pthread_detach(pthread_self());
ThreadPool *self = (ThreadPool *)arg;
//一个线程可以在被调度期间连续执行多个任务
while(1){
self->LockQueue();
//if改while防止伪唤醒,唤醒后再确认一下条件,确实是该条件唤醒的则执行while()下一步
while(self->IsQueueEmpty()){
self->Wait();
}
T t;
self->Pop(t);
//一经取出就不在队列中了,其他线程看不到了
self->UnlockQueue();
t.Run();
}
}
~ThreadPool(){
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
}
}
#include "ThreadPool"
#include
#include
int main(){
ThreadPool<Task> *tp = new ThreadPool<Task>();
tp->InitThreadPool(); //核心一步,才创建线程池,一经创建则等待push任务唤醒
srand((usigned long)time(0));
const char *op = "+-*/%";
while(1){
int x = rand()%100+1;
int y = rand()%100+1;
Task t(x, y, op[x%5]);
tp->Push(t);
sleep(1);
}
return 0;
}
