当前位置:网站首页>Sandbox中的进程/线程相关-1
Sandbox中的进程/线程相关-1
2022-08-09 12:45:00 【养猪去】
文章目录
进程/线程相关
线程相关
background information
线程和进程的理论概念不再赘述。
Linux 中,系统是不认识线程还是进程的,它只认识 task。
下面的阐述都是 Unix like 下的有关线程的语义。
主线程和子线程
- 共享: 用户区内,除了栈区是不共享的,其余都是共享的。
- 不共享: 栈区(当有 1 主 + 4 子线程时候,栈区会被平分为 5 份)
多进程共享的资源(fork、clone出的子进程和父进程):
代码
文件描述符
内存映射区 –mmap
多线程共享的资源:堆
全局变量
线程号和线程 ID 是有区别的
查看方式: 找到程序的进程 ID后,ps -Lf $(pid)
,LWP那一列即为线程ID。
pthread_create
- 头文件:
#include<pthread.h>
pthread非linux系统的默认库, 需手动链接-线程库 -lpthread
函数说明:
返回成功时,由 tidp 指向的内存单元被设置为新创建线程的线程ID。a
ttr参数用于指定各种不同的线程属性。
新创建的线程从start_rtn函数的地址开始运行,该函数只有一个万能指针参数arg。
如果需要向start_rtn函数传递的参数不止一个,那么需要把这些参数放到一个结构体中,然后把这个结构的地址作为arg的参数传入。函数定义
int pthread_create(pthread_t *tidp,const pthread_attr_t *attr, void *(*start_rtn)(void*),void *arg);
参数说明:
第一个参数为指向线程标识符的指针。
第二个参数用来设置线程属性。
第三个参数是线程运行函数的起始地址。
最后一个参数是运行函数的参数。返回值
若线程创建成功,则返回0。若线程创建失败,则返回出错编号,并且*thread中的内容是未定义的。代码
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
int num = 13; //设置为全局变量,在全局区域,共享
void* myfun(void* arg);
int main(int argc, char *argv[])
{
void* p = (void *)# //传一个地址进去(voi* 也是 4 个字节)
pthread_t id[5] = {
0};
for (int i = 0; i < 5; i++) {
pthread_create(&(id[i]), NULL, myfun, p);
printf("i = %d, thread id: %ld\n", i, id[i]);
}
return 0;
}
void* myfun(void* arg)
{
printf("num = %d, child thread id: %ld\n", (*((int *)arg))++, pthread_self());
return NULL;
}
pthread_join
pthread_join()即是子线程合入主线程,主线程阻塞等待子线程结束,然后回收子线程资源。
注意,默认情况下,资源是不会随着子线程的exit或return而回收的。
- 头文件:
#include <pthread.h>
- 函数说明:
thread_join()函数,以阻塞的方式等待thread指定的线程结束。当函数返回时,被等待线程的资源被收回。
如果线程已经结束,那么该函数会立即返回。并且thread指定的线程必须是 joinable 的。 - 函数定义
int pthread_join(pthread_t thread, void **retval);
thread: 线程标识符,即线程ID,标识唯一线程。
retval: 用户定义的指针,用来存储被等待线程的返回值。
返回值
0代表成功。 失败,返回的则是错误号。示例代码:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
void *thread_function(void *arg) {
int i;
for (i = 0; i < 8; i++) {
printf("Thread working... %d \n", i);
sleep(1);
}
return NULL;
}
int main(void) {
pthread_t mythread;
if (pthread_create(&mythread, NULL, thread_function, NULL)) {
printf("error creating thread.");
abort();
}
if (pthread_join(mythread, NULL)) {
printf("error join thread.");
abort();
}
printf("thread done! \n");
return 0;
}
/* 输出 Thread working...! 0 Thread working...! 1 Thread working...! 2 Thread working...! 3 Thread working...! 4 Thread working...! 5 Thread working...! 6 Thread working...! 7 thread done! */
如果去掉pthread_join
的调用的话,
输出为:
thread done!
Thread working... 0
Process finished with exit code 0
也就是说,子线程来不及执行它的函数,就因为父线程的死亡而被迫终结了。
pthread_detach
- 头文件:
#include <pthread.h>
函数说明:
pthread_join()函数的替代函数,可回收创建时detachstate属性设置为PTHREAD_CREATE_JOINABLE的线程的存储空间。
该函数不会阻塞父线程。
pthread_join()函数用于只是应用程序在线程tid终止时回收其存储空间。函数定义
int pthread_detach(pthread_t tid);
- 返回值
thread_detach() 在调用成功完成之后返回零。其他任何返回值都表示出现了错误。
注意,即使如此,父线程退出时,子线程仍然会强制退出。
pthread_cancel
函数说明:
发送终止信号给thread线程,如果成功则返回0,否则为非0值。发送成功并不意味着thread会终止。函数定义:
int pthread_cancel(pthread_t thread)
- 示例代码:
/** * @Author: 吉松阳 * @Date: 2021/9/26 * @Description: */
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
void print_message_function(void *ptr);
int main() {
pthread_t thread1;
pthread_create(&thread1, NULL, (void *) &print_message_function, (void *) 0);
sleep(3);
printf("main thread\n");
pthread_cancel(thread1);
sleep(7);
exit(0);
}
void print_message_function(void *ptr) {
pthread_detach(pthread_self());
sleep(6);
printf("child thread\n");
pthread_exit(0);
}
// 实验证明 pthread_exit 确实起作用了
- 参考链接:
线程取消(pthread_cancel)
信号处理相关
raise
- 头文件:
#include <signal.h>
函数说明:
C 库函数, 会促使生成信号 sig。sig 参数与 SIG 宏兼容。函数定义
// sig -- 要发送的信号码。
int raise(int sig)
查看所有信号:使用 kill -l
[email protected]:~$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
值得注意的是,
当一个进程调用fork时,因为子进程在开始时复制父进程的存储映像,信号捕捉函数的地址在子进程中是有意义的,所以子进程继承父进程的信号处理方式。
但是当子进程调用exec后,因为exec运行新的程序后会覆盖从父进程继承来的存储映像。
那么信号捕捉函数在新程序中已无意义,所以exec会将原先设置为要捕捉的信号都更改为默认动作。
- 返回值
如果成功该函数返回零,否则返回非零。
signal
- 头文件:
#include <signal.h>
函数说明:
C 库函数,设置一个函数来处理信号,即带有 sig 参数的信号处理程序。函数定义
void (*signal(int sig, void (*func)(int)))(int)
参数说明:
sig – 在信号处理程序中作为变量使用的信号码。下面是一些重要的标准信号常量
func – 一个指向函数的指针。它可以是一个由程序定义的函数,也可以是下面预定义函数之一。
- SIG_DFL 默认的信号处理程序。
- SIG_IGN 忽视信号。
返回值
该函数返回之前的信号处理程序实例代码
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
void signal_catchfunc(int);
int main() {
int ret;
signal(SIGINT, signal_catchfunc);
printf("开始生成一个信号\n");
ret = raise(SIGINT);
if (ret != 0) {
printf("错误,不能生成SIGINT信号\n");
exit(0);
}
printf("退出....\n");
return 0;
}
void signal_catchfunc(int signal) {
printf("捕获信号\n");
}
sandbox使用的信号
信号的共达60余个,这里只介绍一下sandbox中使用的信号。
SIGUSR1/SIGUSR2
SIGUSR1 用户自定义信号 默认处理:进程终止;
SIGUSR2 用户自定义信号默认处理:进程终止。
SIGSEGV
在POSIX兼容的平台上,SIGSEGV是当一个进程执行了一个无效的内存引用,或发生段错误时发送给它的信号。
SIGSEGV的符号常量在头文件signal.h
中定义。
因为在不同平台上,信号数字可能变化,因此最好使用符号信号名。通常,它是信号#11。
SIGSEGV维基百科
边栏推荐
- 中断系统结构及中断控制详解
- WebView injects Js code to realize large image adaptive screen click image preview details
- 在“Extend the Omniverse”比赛中构建用于 3D 世界的工具
- 单面线路板与精密多层PCB线路板区别有哪些?
- leetcode 20. Valid Parentheses 有效的括号(中等)
- LnReader编译
- 新起之秀 DPU,正在掀起数据中心变革!
- read stream 特别注意
- 用plot_hist_numeric()实现画直方图
- [FPGA Tutorial Case 48] Image Case 8 - Realization of Converting RGB Image to HSV Image Based on FPGA, Assisted Verification by MATLAB
猜你喜欢
随机推荐
Jenkins API groovy调用实践: Jenkins Core Api & Job DSL创建项目
Flutter Getting Started and Advanced Tour (8) Button Widget
Customize VIEW to realize in-app message reminder to rotate up and down
ERP不规范,同事两行泪 (转载非原创)
5G China unicom AP:B SMS ASCII 转码要求
kustomize entry example and basic syntax instructions
read stream 特别注意
Redis源码剖析之数据过期(expire)
生成上传密钥和密钥库
Flutter入门进阶之旅(二)Hello Flutter
World's 4th mad scientist dies on his 103rd birthday
Say goodbye to the AI era of hand looms
用场景定义硬件,英码科技破解“边缘计算”密码
阿里大淘系模型治理阶段性分享
基于 R 语言的判别分析介绍与实践 LDA和QDA
Compensation transaction and idempotency guarantee based on CAP components
gin的中间件和路由分组
十六进制字符→十进制数字
Redis源码剖析之字典(dict)
如何修改data work上jdbc驱动的版本