新桥做网站,建设类网站有哪些,成交型网站建设价格,wordpress安装 简书pthread 线程 概念 #xff1a;线程是轻量级进程#xff0c;一般是一个进程中的多个任务。 进程是系统中最小的资源分配单位. 线程是系统中最小的执行单位。 优点#xff1a; 比多进程节省资源#xff0c;可以共享变量
进程会占用线程是轻量级进程一般是一个进程中的多个任务。 进程是系统中最小的资源分配单位. 线程是系统中最小的执行单位。 优点 比多进程节省资源可以共享变量
进程会占用左右的空间线程只会占用一部分大概的空间
进程的父子不会共享,但一个进程之间的线程的资源可以共享.
进程的父子不是平级关系,线程是平级关系 特征ss 1、共享资源 2、效率高 30% 3、三方库 pthread clone posix 3.1 编写代码头文件 pthread.h 3.2 编译代码加载库 -lpthread library libpthread.so (linux库) gcc 1.c -lpthread -lc 缺点 1线程和进程相比稳定性稍微差些 2线程的调试gdb相对麻烦些。 info thread *1 2 3 thread 3 线程与进程区别 资源 线程比进程多了共享资源。 IPC 线程又具有部分私有资源。 进程间只有私有资源没有共享资源。 空间 进程空间独立不能直接通信。 线程可以共享空间可以直接通信。 进程解决相对复杂的问题,线 程解决相对复杂的问题.
共同点:
二者都可以并发 3、线程的设计框架 posix
创建多线程 》线程空间操作 》线程资源回收 errno strerrorerrno perror(); 3.1 创建多线程 int pthread_create( pthread_t *thread , const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); 功能该函数可以创建指定的一个线程。 参数thread 线程id需要实现定义并由该函数返回。 attr 线程属性一般是NULL表示默认属性。 start_routine 指向指针函数的函数指针。 本质上是一个函数的名称即可。称为 th 回调函数,是线程的执行空间。 { } arg 回调函数的参数即参数3的指针函数参数。 返回值成功 0 失败 错误码
注意一次pthread_create执行只能创建一个线程。 每个进程至少有一个线程称为主线程。 主线程退出则所有创建的子线程都退出。暂时先用while(1); 主线程必须有子线程同时运行才算多线程程序。 线程id是线程的唯一标识是CPU维护的一组数字。 pstree 查看系统中多线程的对应关系。 多个子线程可以执行同一回调函数。 ps -eLf 查看线程相关信息Low Weigth Process ps -eLo pid,ppid,lwp,stat,comm
#includestdio.h
#includestdlib.h
#includeunistd.h
#includestring.h
#includepthread.h
void *th1(void*arg)
{while(1){printf(发送视频\n);sleep(1);}
}void *th2(void*arg)
{while(1){printf(接受控制\n);}
}int main(int argc, const char *argv[])
{pthread_t tid1,tid2;pthread_create(tid1,NULL,th1,NULL);pthread_create(tid2,NULL,th2,NULL);while(1);return 0;
}
main 函数开始执行。使用 pthread_create 创建了两个线程 tid1 和 tid2。th1 线程开始执行其无限循环并在每次迭代中打印 发送视频然后暂停一秒。同时几乎是同时th2 线程也开始执行其无限循环不断打印 接受控制。因为两个线程是并发执行的所以它们之间没有固定的打印顺序。这取决于操作系统调度器的决策哪个线程在何时获得CPU时间片。main 函数中的 while(1); 是一个空循环它使主线程保持活动状态防止程序立即退出。然而这个空循环并没有为程序提供任何有用的功能通常你可能会使用某种形式的线程同步或等待如 pthread_join来确保主线程在所有其他线程完成后才退出。
此时输出是乱的,是由于
线程调度是由操作系统控制的它决定哪个线程在何时运行。这取决于许多因素包括线程优先级、系统负载、可用的CPU核心数量等。由于两个线程都在无限循环中并且没有同步机制如互斥锁、条件变量等所以它们会尽可能快地交替执行或并行执行如果系统有多个CPU核心导致输出看起来没有规律。
2、pthread_t pthread_self(void); unsigned long int; %lu 获取线程号 功能获取当前线程的线程id 参数无 返回值成功 返回当前线程的线程id 失败 -1 syscall(SYS_gettid); 这个方法重启后失效 alias gccgcc -g -pthread unalias gcc
永久起作用 cd ~ //家目录 vim .bashrc alias gccgcc -g -pthread :wq
source .bashrc 生效
#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include pthread.h
void *th1 (void*arg)
{while(1){printf(发送视频 %lu\n,pthread_self());sleep(1);}
}void *th2 (void*arg)
{while(1){printf(接受控制 %lu\n,pthread_self());sleep(1);}
}int main(int argc, char *argv[])
{pthread_t tid1,tid2;pthread_create(tid1,NULL,th1,NULL);pthread_create(tid2,NULL,th2,NULL);printf(main th %lu\n,pthread_self());while(1);return 0;
}使用pthread_create创建两个线程tid1运行th1和tid2运行th2。打印主线程的ID。使用while(1);使主线程进入无限循环以保持程序运行。否则当主线程结束时程序可能会立即终止导致其他线程也被终止
练习题 设计一个多线程程序至少有三个子线程 每个线程执行不同的任务并实时打印执行 过程同时表明身份。 eg: ./a.out tid xxx... zheng ... tid2 xxx wozai. tid3 xxx wozai ssss 线程的退出
1.直接用return;
2 自行退出 》自杀 》子线程自己退出 exit(1); void pthread_exit(void *retval); exit return p; 功能子线程自行退出 参数 retval 线程退出时候的返回状态临死遗言。 返回值无 th { int a 10; pthread_exit(a); } join(,ret) #include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include pthread.h
void *th1 (void*arg)
{int i 10;while(i--){printf(发送视频 %lu\n,pthread_self());sleep(1);}pthread_exit(NULL);//return NULL;
}void *th2 (void*arg)
{int i 10;while(i--){printf(接受控制 %lu\n,pthread_self());sleep(1);}pthread_exit(NULL);
}int main(int argc, char *argv[])
{pthread_t tid1,tid2;pthread_create(tid1,NULL,th1,NULL);pthread_create(tid2,NULL,th2,NULL);printf(main th %lu\n,pthread_self());while(1);return 0;
} 3. 强制退出 》他杀 》主线程结束子线程 int pthread_cancel(pthread_t thread); 功能请求结束一个线程 (在主线程种调用 写入某个线程id号,可以关闭该线程) 参数thread 请求结束一个线程tid(想要关闭的线程id号) 返回值成功 0 失败 -1
#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include pthread.h
void *th1 (void*arg)
{while(1){printf(发送视频\n);sleep(1);}
}void *th2 (void*arg)
{while(1){printf(接受控制\n);sleep(1);}
}int main(int argc, char *argv[])
{pthread_t tid1,tid2;pthread_create(tid1,NULL,th1,NULL);pthread_create(tid2,NULL,th2,NULL);int i 0 ;while(1){i;if(3 i ){pthread_cancel(tid1);}if(5 i){pthread_cancel(tid2);}sleep(1);}return 0;
} 作业 创建一个多线程程序至少有10个子线程 每个线程有会打印不同的数据同时表明身份。 线程的回收 1、线程的回收机制 》不同与进程没有孤儿线程和僵尸线程。 》主线程结束任意生成的子线程都会结束。 》 子线程的结束不会影响主线程的运行。 char * retval ; retval; 1 int * retval; int pthread_join(pthread_t thread, void **retval); 功能通过该函数可以将指定的线程资源回收该函数具有阻塞等待功能如果指定的线程没有结束则回收线程会阻塞。 参数thread 要回收的子线程tid retval 要回收的子线程返回值/状态。》ptread_exit(值); 返回值成功 0 失败 返回一个错误号,是一个大于零的数 失败可以用 #include unistd.h
#include string.h
#include pthread.h
void *th1 (void*arg)
{int i 10;while(i--){printf(发送视频\n);sleep(1);}
}void *th2 (void*arg)
{int i 10;while(i--){printf(接受控制\n);sleep(1);}
}int main(int argc, char *argv[])
{pthread_t tid1,tid2;pthread_create(tid1,NULL,th1,NULL);int ret pthread_create(tid2,NULL,th2,NULL);if(ret!0){// perror()fprintf(stderr,error %s\n,strerror(ret));//exit();}pthread_join(tid1,NULL);pthread_join(tid2,NULL);return 0;
}子线程的回收策略 1、如果预估子线程可以有限范围内结束则正常用pthread_join等待回收。 2、如果预估子线程可能休眠或者阻塞则等待一定时间后强制回收。 3、如果子线程已知必须长时间运行则不再回收其资源。 线程的参数返回值
1、传参数 传整数 》int add(int a,int b); ///a b 形参 add(x,y); x y 实参 pthread_create(tid,NULL,fun,x); fun void * fun(void * arg); 练习创建一个子线程并向该线程中传入一个字符在 线程中打印输出。 在此基础上向子线程中传入一个字符串并在 子线程中打印输出。 add(int a, int b) { int c ab; char buf[] return c; } 5 int d add(2,3);
#include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include pthread.hvoid* th(void* arg)
{static int a 20;return a;
}int main(int argc, char *argv[])
{pthread_t tid;void* ret;pthread_create(tid,NULL,th,NULL);pthread_join(tid,ret);printf(ret %d\n,*(int*)ret);return 0;
} 传字符串 栈区字符数组 字符串常量 char *p hello; 堆区字符串 char *pc (char *)malloc(128); ptread_create(tid,NULL,fun,pc); pthread_join(tid,NULL); free(pc); fun(void *arg) { char * pc (char *)arg ; printf(%s \n,pc); %c }
栈区
#include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include pthread.hvoid* th(void* arg)
{static char buf[256]{0};strcpy(buf,要消亡了\n);return buf;
}int main(int argc, char *argv[])
{pthread_t tid;void* ret;pthread_create(tid,NULL,th,NULL);pthread_join(tid,ret);printf(ret %s\n,(char*)ret);return 0;
}
堆区:
#include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include pthread.hvoid* th(void* arg)
{char * tmp (char* )arg;strcpy(tmp,hello);return tmp;
}int main(int argc, char *argv[])
{pthread_t tid;char * p (char*)malloc(50);void* ret;pthread_create(tid,NULL,th,p);pthread_join(tid,ret);printf(ret %s\n,(char*)ret);free(p);return 0;
}传结构体 1、定义结构体类型 2、用结构体定义变量 3、向pthread_create传结构体变量 4、从fun子线程中获取结构体数据
#include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include pthread.h
typedef struct
{char * p;int a;
}TH_ARG;
void* th(void* arg)
{TH_ARG * tmp (TH_ARG* )arg;strcpy(tmp-p,hello);//strcpy( ((TH_ARG*)arg)-p ,hello);tmp-a 10;return tmp;
}int main(int argc, char *argv[])
{pthread_t tid;int a 20;char * p (char*)malloc(50);TH_ARG arg;arg.a a;arg.p p;void* ret;pthread_create(tid,NULL,th,arg);pthread_join(tid,ret);printf(ret %s %d\n,((TH_ARG*)ret)-p,((TH_ARG*)ret)-a);free(p);return 0;
}练习 定义一个包含不同数据类型的测试结构体 并向子线程传参数同时在子线程中打印输出。 定义一个回调函数可以完成计算器的功能 定义一个数据结构体可以一次传入不同的数据 和计算方式并将结果打印输出。 //2 3.6 // 2 3 23 // 8 * 6 typedef strcut { float a; float b; char c;// - * / float d; }JSQ;
返回值pthread_exit(0) pthread_exit(9); pthread_join(tid,NULL); pthread_join(tid,?); 10; -10; int * p malloc(4); *p -10; 1、pthread_exit(?) ? void * retval; 纯地址
2、pthread_join(tid,?) ? void **retval; 地址的地址 原理子线程退出的时候可以返回一个内存地址 改值所在的内存中可以存储任何数据只要 地址存在则数据都可以正常返回。 地址有三种 0、栈区变量 错误子线程结束该地址失效。 1、全局变量 失去意义本质可以直接访问。 2、静态变量 3、堆区变量 主线程通过一个地址形式的变量来接受子进程 返回的地址变量就可以将该地址中的数据取到。 练习从子线程中申请一块堆区内存并存字符串 将该字符串以返回值形式返回到主线程并打印输出。 设置分离属性目的线程消亡自动回收空间。 主线程没有空,才设置分离属性来回收. attribute int pthread_attr_init(pthread_attr_t *attr); 功能初始化一个attr的变量 参数attr需要变量来接受初始值 返回0 成功 非0 错误 int pthread_attr_destroy(pthread_attr_t *attr); 功能销毁attr变量。 attr属性变量 返回0 成功 非0 错误 man -k int pthread_attr_setdetachstate(pthread_attr_t *attr , int detachstate); 功能把一个线程设置成相应的属性 参数attr属性变量有init函数初始化他。 detachstate有2个可选值 PTHREAD_CREATE_DETACHED设置分离属性。 第二种设置分离属性int pthread_deatch(pthread_t thread); 功能设置分离属性 参数线程id号填自己的id do{ }while()
#include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include pthread.h
void* th(void* arg)
{pthread_detach(pthread_self());return NULL;
}int main(int argc, char *argv[])
{pthread_t tid;int i 0 ;for(i0;i50000;i){int ret pthread_create(tid,NULL,th,NULL);if(ret!0){break;}// pthread_detach(tid);}printf(%d \n,i);return 0;
}void pthread_cleanup_push(void (*routine)(void *) void *arg); 功能注册一个线程清理函数 参数routine线程清理函数的入口 arg清理函数的参数。 返回值无 void pthread_cleanup_pop(int execute); 功能调用清理函数 execute非0 执行清理函数 0 不执行清理 返回值无
do {
}while(1)
process thread fork pthread_create getpid,ppid, pthread_self exit, pthread_exit wait,waitpid, pthread_join kill, pthread_cancel atexit pthread_clean, exec system---fork-exec (ls)