目录
只有认知的突破 💫才能带来真正的成长 💫编程技术的学习 💫没有捷径 💫一起加油💫

🍁感谢各位的观看 🍁欢迎大家留言 🍁咱们一起加油 🍁努力成为更好的自己🍁
线程
概念:进程中的某个分开的执行流。
总结:在Linux系统中,没有线程这一说法。只有轻量级进程。
概念图
至于进程和线程的关系,如下图所示。

提示
- 进程是系统资源划分的最小单位,线程是进程资源划分的最小单位。
如下所示的代码。
cpp
#include <iostream>
#include <pthread.h>
#include <string>
#include <unistd.h>
void* fun(void*mesg)
{
std::string messge=(const char*)(mesg); //转化为string字符
int i=10;
while(i)
{
std::cout<<messge<<std::endl;
sleep(1);
i--;
}
}
int main()
{
pthread_t pwd;
std::string ptr="我是一个线程";
//创建线程,并分开执行流
pthread_create(&pwd,nullptr,&fun,(void*)ptr.c_str());
int i=20;
//主线程执行
while(i)
{
std::cout<<"我是进程"<<std::endl;
sleep(1);
i--;
}
return 0;
}

现象:代码的执行流被分流了,分为主执行流和分支流。
线程的控制
线程的创建
函数:int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine)(void*), void *arg)
参数:
-
thread:返回线程ID。 -
attr:设置线程的属性,attr为NULL表示使用默认属性。一般直接设为NULL。 -
start_routine:是个函数地址,线程启动后要执行的函数。 -
arg:传给线程启动函数的参数。这个参数会传给start_routine函数。
如下所示的代码。
cpp
void* fun(void*mesg)
{
std::string messge=(const char*)(mesg); //转化为string字符
int i=10;
while(i)
{
std::cout<<messge<<std::endl;
sleep(1);
i--;
}
}
****************************************************************
pthread_t pwd;
std::string ptr="我是一个线程";
//创建线程,并分开执行流
pthread_create(&pwd,nullptr,&fun,(void*)ptr.c_str());
thread参数
它返回的是在pthread库中,为进程创建的一个结构体对象的地址,类似于之前的FILE*指针。而这个结构体里面保存着线程所处的进程pid,自己的pid和自己的资源。
提示:对于线程库为这个线程创建的结构体对象,我们称为tcb。
如下所示的结构体。
cpp
线程的tcb
struct pthread
{
/* Thread ID - which is also a 'is this thread descriptor (and
therefore stack) used' flag. */
pid_t tid; //线程的
/* Process ID - thread group ID in kernel speak. */
pid_t pid; //所处进程的
}

查询线程的 指令
指令:ps -aL
cpp
$ ps -aL | head -1 && ps -aL | grep mythread
PID LWP TTY TIME CMD
2711838 2711838 pts/235 00:00:00 mythread
2711838 2711839 pts/235 00:00:00 mythread
-L 选项:打印线程信息
线程的终止
函数1
函数:void pthread_exit(void *value_ptr)。哪个线程调用,就终止哪个线程。
参数
void *value_ptr:相当于exit(退出码),退出码。它所指向的变量必须是在堆上开辟的空间或者全局变量,千万不可是局部变量。
**注意:**线程的退出千万不可以用exit(),否则所有的线程和进程都会退出。
如下所示的代码。
cpp
// #include <iostream>
#include <pthread.h>
#include <string>
#include <unistd.h>
#include <iostream>
int p=10; //或全局变量
void* fun(void*mesg)
{
std::string messge=(const char*)(mesg); //转化为string字符
int i=4;
while(i)
{
std::cout<<messge<<std::endl;
sleep(1);
i--;
}
//或堆上开辟的空间
// int*p=new int(10);
// *p=10;
pthread_exit((void*)&p);
}
int main()
{
pthread_t pwd1;
std::string ptr1="我是一个线程1";
//创建线程,并分开执行流
pthread_create(&pwd1,nullptr,&fun,(void*)ptr1.c_str());
void*ret;
pthread_join(pwd1,&ret);
std::cout<<"获得退出信息"<<*(int*)(ret)<<std::endl;
return 0;
}
函数2
函数:int pthread_cancel(pthread_t thread)。用来终止指定的线程。
如下所示的代码。
cpp
#include <pthread.h>
#include <string>
#include <unistd.h>
#include <iostream>
void* fun(void*mesg)
{
std::string messge=(const char*)(mesg); //转化为string字符
int i=4;
while(i)
{
std::cout<<messge<<std::endl;
sleep(1);
i--;
}
}
int main()
{
pthread_t pwd1;
std::string ptr1="我是一个线程1";
//创建线程,并分开执行流
pthread_create(&pwd1,nullptr,&fun,(void*)ptr1.c_str());
sleep(2);
pthread_cancel(pwd1); //取消指定的线程
void*ret;
pthread_join(pwd1,&ret);
std::cout<<"获得退出信息"<<*(int*)(ret)<<std::endl;
return 0;
}
线程等待
函数:int pthread_join(pthread_t thread, void **value_ptr),等待指定的线程。
它会阻塞的等待。
为什么需要线程等待?
-
已经退出的线程,其空间没有被释放,仍然在进程的地址空间内。
-
创建新的线程不会复用刚才退出线程的地址空间。
线程分离
提示:如果不关心线程的返回值,join是⼀种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。
函数:int pthread_detach(pthread_t thread),分离指定线程。
函数:pthread_t pthread_self(void),线程获取自己的ID。
如下所示的代码。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void *thread_run(void *arg)
{
pthread_detach(pthread_self());
printf("%s\n", (char *)arg);
return NULL;
}
int main(void)
{
pthread_t tid;
if (pthread_create(&tid, NULL, thread_run, (void*)"thread1 run...") != 0)
{
printf("create thread error\n");
return 1;
}
int ret = 0;
sleep(1); // 很重要,要让线程先分离,再等待
if (pthread_join(tid, NULL) == 0)
{
printf("pthread wait success\n");
ret = 0;
}
else
{ //因为线程分离了,所以无需等待,自然就会等待失败。
printf("pthread wait failed\n");
ret = 1;
}
return ret;
}