微平台网站支持html5实现游戏,关键词推广方法,桂林论坛天涯社区,wordpress 重置密码文章目录 1.什么是线程2.线程vs进程3.线程调度4.线程控制4.1 POSIX线程库4.2创建线程4.3线程终止4.4线程等待4.5线程分离 5、线程封装 1.什么是线程 在Linux操作系统中#xff0c;线程是进程内部的一个执行流。在Linux操作系统下#xff0c;执行流统称为轻量级进程#xff0… 文章目录 1.什么是线程2.线程vs进程3.线程调度4.线程控制4.1 POSIX线程库4.2创建线程4.3线程终止4.4线程等待4.5线程分离 5、线程封装 1.什么是线程 在Linux操作系统中线程是进程内部的一个执行流。在Linux操作系统下执行流统称为轻量级进程也是task_struct作为数据结构简称LWP也就是说在Linux下线程是通过LWP模拟实现的。 2.线程vs进程 进程是承当资源分配的基本实体线程是os调度的基本单位。线程共享进程的地址空间即共享数据。 1文件描述符 2信号处理方式 3当前工作目录 4用户id和组id线程也有自己独立的一些数据 1栈 2寄存器 3线程ID 4调度优先级 5errno (6)信号屏蔽字 3.线程调度 如果线程所属的进程不被调度那么该进程内的所有线程包括主线程和其他任何线程通常也不会被调度执行。线程调度也是受到优先级、调度策略等影响。线程调度的时机 时间片用完操作系统为每个线程分配一个时间片当线程的时间片用完时操作系统会将调度权交给其他线程。 阻塞操作当线程执行了一个阻塞操作例如等待输入、等待磁盘读写等操作系统会将线程切换到阻塞状态同时调度其他可运行线程。 优先级调度线程的优先级可能会影响调度。当高优先级的线程就绪时操作系统可能会将其切换到运行状态同时调度低优先级的线程。 睡眠和唤醒线程可以通过调用sleep()或wait()等方法主动让出CPU进入睡眠状态。当休眠时间到期或条件满足时线程会被唤醒并重新调度。 中断处理当线程遇到硬件中断时操作系统可能会中断当前线程的执行切换到中断处理程序的上下文。 4.线程控制
4.1 POSIX线程库 与线程有关的函数构成了⼀个完整的系列绝⼤多数函数的名字都是以“pthread_”打头的。要使⽤这些函数库要通过引⼊头⽂ pthread.h。链接这些线程函数库时要使⽤编译器命令的“-lpthread”选项。 4.2创建线程
函数原型
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);参数 thread指向 pthread_t 类型的指针。 用途用于存储新创建的线程的标识符ID。 调用成功后这个参数指向的位置会被赋予新线程的ID。 注意在使用这个线程ID之前不需要对其进行任何初始化。attr指向 pthread_attr_t 类型的指针该类型是一个结构体用于指定线程的属性。 用途允许调用者设置新线程的属性如是否分离detach、堆栈大小、调度策略和优先级等。 默认值如果设置为 NULL则使用默认属性创建线程。vstart_routine函数指针指向一个返回 void类型并接受一个 void 类型参数的函数。 用途这是新线程将要执行的函数的地址。该函数称为线程的启动例程start routine或线程函数。 参数该函数接受一个 void* 类型的参数arg允许调用者向线程函数传递任意数据。 返回值线程函数的返回值将被传递给 pthread_exit 函数如果线程调用它或作为线程的退出状态如果线程直接返回。arg void* 类型的指针。 用途传递给线程函数的参数。它允许调用者向线程函数传递任意数据。 注意在实际使用中通常需要将这个参数转换为适当的类型以便在线程函数内部使用。 返回值 成功返回 0。失败返回一个非零的错误码这些错误码通常定义在 pthread.h 头文件中并且可以通过 strerror 或 perror 函数转换为可读的错误信息。 功能 用于创建新线程的函数。 例子 创建一个线程并执行函数
#includeiostream
#includepthread.h
#include unistd.h//3.线程会执行到这里
void * func(void *arg)
{while(true){printf(%s\n,(char*)arg);sleep(1);}
}int main()
{//1.创建线程pthread_t pt;pthread_create(pt,nullptr,func,(void*)我是新线程);//2.主线程while(true){printf(我是一个主线程\n);sleep(1);}return 0;
}现象主线程和新线程都在执行各自的任务。
查看LWP
ps -aL | head -1 ps -aL | grep test现象pid都相同说明是同一个进程lwp区分不同线程。
补充 在系统内核中只认识LWP而我们用户需要使用线程就需要用thread标识符去操作线程这是因为 POSIX线程库给我们用户进行了封装这类似于文件描述符bf和FILE*的关系。 4.3线程终止
4.3.1 从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit结束进程。
4.3.2pthread_ exit 功能 结束线程。 函数原型
void pthread_exit(void *retval);参数 retval 是一个指向返回值的指针这个返回值可以被其他线程通过 pthread_join 函数线程等待的函数获取。如果线程没有设置返回值即不关心其退出状态可以传递 NULL 作为 retval 的参数。 4.3.3pthread_ cancel 功能 请求取消指定线程的函数。当一个线程调用 pthread_cancel 并向另一个线程发送取消请求时被请求的线程可以选择在合适的时机终止执行。 函数原型
int pthread_cancel(pthread_t thread);参数 thread: 线程标识符。 返回值 成功时返回 0。失败时返回一个非零的错误码。 4.4线程等待
4.4.1为什么进行等待呢 释放线程的空间有点像进程等待。获取线程的退出状态。 4.4.2pthread_join 功能 用于等待指定线程终止的函数。调用 pthread_join 的线程通常是主线程或另一个线程会被阻塞直到被等待的线程结束执行或取消并取到被等待线程的返回值或处理其终止后的资源清理。 函数原型
int pthread_join(pthread_t thread, void **retval);参数 thread : 线程标识符。被等待线程的返回值。 返回值 成功时返回 0。失败时返回一个非零的错误码例如 ESRCH无此线程、EINVAL线程不是可连接的或 EDEADLK检测到死锁。死锁是指两个或两个以上的进程或线程在执行过程中由于竞争资源或者由于彼此通信而造成的一种阻塞的现象若无外力作用它们都将无法推进下去。 具体解释 如果thread线程通过return返回,value_ ptr所指向的单元⾥存放的是thread线程函数的返回值。如果thread线程被别的线程调⽤pthread_ cancel异常终掉,value_ ptr所指向的单元⾥存放的是常 数PTHREAD_ CANCELED。如果thread线程是⾃⼰调⽤pthread_exit终⽌的,value_ptr所指向的单元存放的是传给 pthread_exit的参数。如果对thread线程的终⽌状态不感兴趣,可以传NULL给value_ ptr参数。 例子 创建新线程再使用pthread_ exit结束线程再用主线程进行等待。
#includeiostream
#includepthread.h
#include unistd.h
#includestdio.h//3.线程会执行到这里
void * func(void *arg)
{//4.结束自己char * ret new char[50];ret[0] a;ret[1] b;ret[2] \0;pthread_exit((void*)ret);return nullptr;
}int main()
{//1.创建线程pthread_t pt;pthread_create(pt,nullptr,func,(void*)我是新线程);//3.主线程进程等待void *ret;int n pthread_join(pt,ret);(void)n; //防止报警告// 5.输出返回值printf(%s\n,(char*)(ret));return 0;
}4.5线程分离
4.5.1为什么要进行线程分离 默认情况下新创建的线程是joinable的线程退出后需要对其进⾏pthread_join操作否则无法释放资源从⽽造成系统泄漏。如果不关心线程的返回值join是⼀种负担这个时候我们可以告诉系统当线程退出时自动释放线程资源。 4.5.2pthread_detach 功能 用于将指定的线程与调用线程通常是主线程分离 函数原型
int pthread_detach(pthread_t thread);参数 thread线程标识符。 返回值 成功时返回 0。失败时返回错误码。常见的错误码包括 ESRCH: 指定的线程标识符无效或不存在。 EINVAL:线程已经是分离状态或已经是 joinable 状态但已经终止。 补充 可以有自己分离也可以由其他线程分离。pthread_self()或者自己的线程标识符。等待和分离是冲突的。 5、线程封装
使用面向对象的方式对线程进行封装。
#ifndef _THREAD_HPP__
#define _THREAD_HPP__#include iostream
#include string
#include pthread.h
#include functional
#include sys/types.h
#include unistd.hnamespace ThreadModule
{//函数包装using func_t std::functionvoid();//线程个数static int number 1;//状态enum class TSTATUS{NEW,RUNNING,STOP};class Thread{private://执行线程函数static void *Routine(void *args){//强制类型转换Thread* thread (Thread*)args;//调用任务thread-_func();return nullptr;}public:Thread(func_t func) : _func(func), _status(TSTATUS::NEW), _joinable(false){_name Thread- std::to_string(number);_pid getpid();}//创建线程bool Start(){if (_status ! TSTATUS::RUNNING) // 保证线程处于非运行状态{int n pthread_create(_tid, nullptr, Routine, (void *)this); // 创建线程if (n ! 0){return false;}_status TSTATUS::RUNNING; // 更新状态return true;}return false;}//取消线程bool Stop(){if(_status TSTATUS::RUNNING) //保证线程处于运行状态{int n pthread_cancel(_tid); //取消线程if(n ! 0){return false;}_status TSTATUS::STOP; // 更新状态return true;}return false;}//等待线程bool Join(){//保证线程不处于分离状态且处于运行状态if(!_joinable _status TSTATUS::RUNNING) { //等待线程默认不关心线程状态int n pthread_join(_tid,nullptr);if(n ! 0){return false;}_status TSTATUS::STOP; // 更新状态return true;}return false;}//线程分离void Detach(){//保证线程不处于分离状态且处于运行状态if(!_joinable _status TSTATUS::RUNNING) {int n pthread_detach(_tid); //进行线程分离if(n ! 0){return ;}std::cout完成线程分离\nstd::endl;_joinable true; //更新分离状态}}bool IsJoinable(){return _joinable;}std::string Name(){return _name;}~Thread() {}private:std::string _name; // 线程namepthread_t _tid; // 线程idpid_t _pid; // 进程idbool _joinable; // 是否是分离的默认不是func_t _func; // 线程执行的任务TSTATUS _status; // 线程状态};
}#endif