【Linux操作系统】进程详解(下)

2023-05-16

文章目录

  • 前言
  • 一、父子进程共用光标问题
    • 1.1 验证
    • 1.2 规避共用光标问题使用多进程拷贝同一个文件
  • 二、进程相关函数
    • 2.1 getpid/getppid函数
    • 2.2 exit/_exit函数
    • 2.3 wait/waitpid函数
  • 三、守护进程
    • 3.1 守护进程的概念
    • 3.2 守护进程的创建流程
    • 3.3 文件描述重定向实例
    • 3.4 创建守护进程实例
  • 总结


前言

前文【Linux操作系统】进程详解(上)详细讲解了进程相关概念的知识。
本文详细介绍进程相关函数和守护进程的相关内容。


一、父子进程共用光标问题

1.1 验证

代码如下(示例):

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PRINT_ERR(msg) \
    do                 \
    {                  \
        printf("%s %s %d\n",__FILE__,__func__,__LINE__);      \
        perror(msg);   \
        return -1;     \
    } while (0)

int main(int argc,const char * argv[])
{
    pid_t pid;
    int fd;
    char ch;
    if((fd=open("./hello.txt",O_RDONLY))==-1)
    {
        PRINT_ERR("open error");
    }
    pid = fork();
    if(pid == -1){
        PRINT_ERR("fork error");
    }else if(pid == 0){
        lseek(fd,5,SEEK_SET);
        read(fd,&ch,1);
        printf("这是子进程%c\n",ch);
    }else{
        sleep(5);
        read(fd,&ch,1);
        printf("这是父进程%c\n",ch);
    }
    close(fd);
    return 0;
}

结果展示:
在这里插入图片描述
总结:
将子进程的光标向后移动5位后输出的是6,父进程因为和子进程共用的一个光标所以父进程在读取的时候并不是1,而是输出了7。
所以为了避免父子进程共用光标的问题,我们不应该在创建进程函数fork前打开文件,应该在各自的进程内打开或者可以打开文件两次,父子进程使用不同的文件描述符。

1.2 规避共用光标问题使用多进程拷贝同一个文件

代码如下(示例):

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PRINT_ERR(msg) \
    do                 \
    {                  \
        printf("%s %s %d\n",__FILE__,__func__,__LINE__);      \
        perror(msg);   \
        return -1;     \
    } while (0)

int file_init_len(const char *src,const char *dest)
{
    int fd,fd1;
    int len;
    if((fd=open(src,O_RDONLY))==-1)
    {
        PRINT_ERR("open src error");
    }
    if((fd1=open(dest,O_RDWR|O_CREAT|O_TRUNC,0666))==-1)
    {
        PRINT_ERR("open dest error");
    }
    len=lseek(fd,0,SEEK_END);
    close(fd);
    close(fd1);
    return len;
}
int file_copy(const char *src,const char *dest,int start,int len)
{
    int fd,fd1;
    int count =0;
    int ret;
    char buf[128]={0};
    if((fd=open(src,O_RDONLY))==-1)
    {
        PRINT_ERR("open src error");
    }
    if((fd1=open(dest,O_WRONLY))==-1)
    {
        PRINT_ERR("open dest error");
    }
    lseek(fd, start, SEEK_SET);
    lseek(fd1, start, SEEK_SET);
    while((ret=read(fd,buf,sizeof(buf)))!=0)
    {
        count+=ret;
        if(count>=len)
        {
            write(fd1,buf,ret-(count-len));
            break;
        }
        write(fd1,buf,ret);
    }
    close(fd);
    close(fd1);
    return 0;
}
int main(int argc,const char * argv[])
{
    pid_t pid;
    int len;
    //1.判断传参是否正确./a.out srcfile destfile
    if(argc!=3)
    {
        fprintf(stderr, "input error,try again\n");
        fprintf(stderr, "usage:./a.out srcfile destfile\n");
        return -1;
    }
    //2.求源文件有多少字节
    len=file_init_len(argv[1],argv[2]);
    //3.父子进程拷贝
    pid = fork();
    if(pid == -1){
        PRINT_ERR("fork error");
    }else if(pid == 0){
        file_copy(argv[1],argv[2],0,len/2);
    }else{
        file_copy(argv[1],argv[2],len/2,len-len/2);
    }
    return 0;
}

结果展示:
在这里插入图片描述
总结:
父子进程调用拷贝函数都打开了文件,所以并不是共用一个光标。

二、进程相关函数

2.1 getpid/getppid函数

#include <sys/types.h>
#include <unistd.h>

pid_t getpid(void);
功能:获取当前进程的进程号
参数:无
返回值:总是会成功了,返回进程的pid

pid_t getppid(void);
功能:获取父进程的进程号
参数:无
返回值:总是会成功了,返回进程的ppid

代码如下(示例):

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#define PRINT_ERR(msg) \
    do                 \
    {                  \
        printf("%s %s %d\n",__FILE__,__func__,__LINE__);      \
        perror(msg);   \
        return -1;     \
    } while (0)

int main(int argc,const char * argv[])
{
    pid_t pid;
    pid = fork();
    if(pid == -1){
        PRINT_ERR("fork error");
    }else if(pid == 0){
        printf("这是子进程");
        printf("pid=%d,ppid=%d\n",getpid(),getppid());
    }else{
        sleep(1);
        printf("这是父进程");
        printf("pid=%d,ppid=%d,cpid=%d\n",getpid(),getppid(),pid);
    }
    return 0;
}

结果展示:
在这里插入图片描述
总结:
getpid用来获取当前进程的进程号,getppid用来获取当前进程的父进程号。

2.2 exit/_exit函数

return本身并不是用来结束进程的,return只有在main函数中,退出main函数的栈的时候整个进程会结束,但是如果return放在其他函数中,并不会结束进程。

#include <unistd.h>
void _exit(int status);
功能:用来结束一个进程,它是系统调用,退出进程的时候不会刷新缓冲区
参数:
    @status:进程退出的时候的状态值 (一般 0成功,1失败)
返回值:无

#include <stdlib.h>
void exit(int status);
功能:用来结束一个进程,它是库函数,退出进程的时候会刷新缓冲区
参数:
    @status:进程退出的时候的状态值 
    (一般 EXIT_SUCCESS 0成功,EXIT_FAILURE 1失败)
返回值:无

exit代码如下(示例):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#define PRINT_ERR(msg) \
    do                 \
    {                  \
        printf("%s %s %d\n",__FILE__,__func__,__LINE__);      \
        perror(msg);   \
        return -1;     \
    } while (0)
    
int main(int argc,const char * argv[])
{
    pid_t pid;
    pid = fork();
    if(pid == -1){
        PRINT_ERR("fork error");
    }else if(pid == 0){
        printf("这是子进程\n");//打印
        printf("111111");//打印
        exit(EXIT_SUCCESS);
        printf("222222\n");//不打印
    }else{
        printf("这是父进程\n");
        while(1);
    }
    return 0;
}

结果展示:
在这里插入图片描述
_exit代码如下(示例):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#define PRINT_ERR(msg) \
    do                 \
    {                  \
        printf("%s %s %d\n",__FILE__,__func__,__LINE__);      \
        perror(msg);   \
        return -1;     \
    } while (0)
    
int main(int argc,const char * argv[])
{
    pid_t pid;
    pid = fork();
    if(pid == -1){
        PRINT_ERR("fork error");
    }else if(pid == 0){
        printf("这是子进程\n");//打印
        printf("111111");//不打印
        _exit(EXIT_SUCCESS);
        printf("222222\n");//不打印
    }else{
        printf("这是父进程\n");
        while(1);
    }
    return 0;
}

结果展示:
在这里插入图片描述
总结:
从以上两个代码进行对比可知
exit在结束进程的时候会进行刷新缓冲区,而_exit则不会刷新缓冲区。

2.3 wait/waitpid函数

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *wstatus);
功能:阻塞等待子进程结束,子进程结束的时候为子进程回收资源,并能够获取到子进程退出时候的状态
参数:
    @wstatus:接收子进程退出的状态 
        (其中8-15这8个bit位是子进程退出的状态)
        (其中0-6这7个bit为是信号号)
返回值:成功返回后回收掉资源的子进程的pid
       失败返回-1,置位错误码
        
 WIFEXITED(wstatus)   //如果子进程是通过exit/_exit/return main 这是正常结束程序的话,它返回真
                      //如果是信号杀死的进程,这个函数返回假
 WEXITSTATUS(wstatus) //获取进程退出的状态
 WIFSIGNALED(wstatus) //如果收到信号这个函数返回真
 WTERMSIG(wstatus)    //获取信号号    

pid_t waitpid(pid_t pid, int *wstatus, int options);
功能:指定回收的子进程资源
参数:
    @pid:进程号
        > 0   回收这个指定pid进程的资源
        -1    回收任意子进程的资源  wait(NULL) == waitpid(-1,NULL,0);
         0    回收同组的任意子进程的资源
	    <-1   首先对这个值取绝对值,和这个绝对值同组的进程的资源都可以被回收         
 @wstatus:子进程退出的状态
 @options:标志位
	    0:阻塞回收资源
        WNOHANG:非阻塞回收资源
返回值:成功返回后回收掉资源的子进程的pid
       失败返回-1,置位错误码

wait代码如下(示例):

#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define PRINT_ERR(msg) \
    do                 \
    {                  \
        printf("%s %s %d\n",__FILE__,__func__,__LINE__);      \
        perror(msg);   \
        return -1;     \
    } while (0)

int main(int argc,const char * argv[])
{
    pid_t pid;

    pid = fork();
    if (pid == -1) {
        PRINT_ERR("fork error");
    } else if (pid == 0) {
        printf("子进程\n"); //会显示
        printf("******************\n"); //会显示
        exit(25); //进程在这里已经结束了,刷新缓冲区
        
    } else {
        int status;
        printf("父进程\n");
        wait(&status);
        if (WIFEXITED(status)) { //子进程正常退出它为真
            printf("status = %d\n", WEXITSTATUS(status)); //打印子进程退出码 25
        } 
        if(WIFSIGNALED(status)){ //子进程被信号杀死它为真
            printf("signo = %d\n",WTERMSIG(status));  //打印信号号
        }
    }
    return 0;
}

结果展示:
在这里插入图片描述

waitpid代码如下(示例):

#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define PRINT_ERR(msg) \
    do                 \
    {                  \
        printf("%s %s %d\n",__FILE__,__func__,__LINE__);      \
        perror(msg);   \
        return -1;     \
    } while (0)

int main(int argc,const char * argv[])
{
     pid_t pid;

    pid = fork();
    if (pid == -1) {
        PRINT_ERR("fork error");
    } else if (pid == 0) {
        printf("子进程\n"); //会显示
        printf("******************\n"); //会显示
        sleep(3);
        exit(125); //进程在这里已经结束了,刷新缓冲区

    } else {
        int status;
        printf("父进程\n");
        waitpid(pid,NULL,0);
    }
    return 0;
}

结果展示:
在这里插入图片描述
总结:
常见的用法: wait(NULL);
wait(NULL) == waitpid(-1,NULL,0);

三、守护进程

3.1 守护进程的概念

守护进程是一个后台运行的进程,不依附当前的终端,随着系统启动而启动,随着系统的终止而终止,相当于window系统的服务。

3.2 守护进程的创建流程

1.创建出一个孤儿进程(不依赖于终端)
父进程结束子进程没被父进程回收

2.新建一个会话

#include <sys/types.h>
#include <unistd.h>

pid_t setsid(void);
功能:创建一个新的会话,如果当前进程不是组长进程,
      创建的会话id,组id就是当前pid的值
参数:
    @无
返回值:成功返回pid,失败返回-1置位错误码

3.将当前进程对应的路径切换到根目录

#include <unistd.h>

int chdir(const char *path);
功能:切换路径的函数
参数:
    @path:路径
返回值:成功返回0,失败返回-1置位错误码

4.设置umask的值

#include <sys/types.h>
#include <sys/stat.h>

mode_t umask(mode_t mask);
功能:设置掩码
参数:
    @mask:掩码的值
返回值:总是会成功,返回mask

5.进行文件描述重定向(脱离终端了,向终端上写东西会有问题)

#include <unistd.h>
dup相当于拷贝,光标互相影响。
int dup(int oldfd);
功能: dup函数的功能,拷贝fd,产生一个新的文件描述符nfd,
       nfd产生的原则最小为使用原则,fd和nfd都可以操作同一个
       文件,fd和nfd共用同一个光标
参数:
    @oldfd:旧的文件描述符
返回值:成功返回nfd,失败返回-1置位错误

重点看dup2
int dup2(int oldfd, int newfd);
功能:dup2函数相当于文件描述符的重定向,
     把newfd重定向到oldfd中了,以后向newfd写内容就是在向odlfd对应的文件中写内容
参数:
    @oldfd:旧文件描述符
    @newfd:新文件描述符
返回值:成功返回newfd,失败返回-1置位错误码

3.3 文件描述重定向实例

dup代码如下(示例):

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PRINT_ERR(msg) \
    do                 \
    {                  \
        printf("%s %s %d\n",__FILE__,__func__,__LINE__);      \
        perror(msg);   \
        return -1;     \
    } while (0)

int main(int argc,const char * argv[])
{
    int fd,nfd;
    if((fd=open("./hi.txt",O_RDONLY))==-1)
    {
        PRINT_ERR("open file error");
    }
    if ((nfd = dup(fd)) == -1)
    {
        PRINT_ERR("dup fd error");
    }
    printf("fd=%d,nfd=%d\n",fd,nfd);
    char ch;
    lseek(fd,3,SEEK_SET);
    read(fd,&ch,1);
    printf("fd=%c\n",ch);
    read(nfd,&ch,1);
    printf("nfd=%c\n",ch);
    return 0;
}

结构展示:
在这里插入图片描述
总结:
dup函数的功能:拷贝fd,产生一个新的文件描述符nfd
nfd产生的原则最小为使用原则,fd和nfd都可以操作hello.txt文件,fd和nfd共用同一个光标

dup2代码如下(示例):

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PRINT_ERR(msg)                                      \
    do                                                      \
    {                                                       \
        printf("%s %s %d\n", __FILE__, __func__, __LINE__); \
        perror(msg);                                        \
        return -1;                                          \
    } while (0)

int main(int argc, const char *argv[])
{
    int fd;
    if ((fd = open("./hi.txt", O_RDWR)) == -1)
    {
        PRINT_ERR("open file error");
    }
    if ((dup2(fd, 1)) == -1)
    {
        PRINT_ERR("dup fd error");
    }
    printf("---------------\n");

    return 0;
}

结构展示:
在这里插入图片描述
总结:
dup2函数相当于文件描述符的重定向,把文件描述符1(标准输出)重定向到fd中了,以后向1写内容就是在向fd对应的文件中写内容。

3.4 创建守护进程实例

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#define PRINT_ERR(msg) \
    do                 \
    {                  \
        printf("%s %s %d\n",__FILE__,__func__,__LINE__);      \
        perror(msg);   \
        return -1;     \
    } while (0)
int main(int argc,const char * argv[])
{
    pid_t pid;
    pid=fork();
    if(pid==-1)
    {
        PRINT_ERR("fork error");
    }
    else if(pid==0)
    {
        //1.创建孤儿进程
        //2.新建会话
        if(setsid()==-1)
        {
            PRINT_ERR("setsid error");
        }
        //3.切换到根目录
        if(chdir("/")==-1)
        {
            PRINT_ERR("chdir error");
        }
        //4.设置掩码
        umask(0);
        //5.关闭其他文件描述符
        //getdtablesize()获取系统中的最大文件描述符个数
        for (int i = 3; i <= getdtablesize(); i++) 
        {
            close(i);
        }
        //6.创建日志文件
        int fd;
        if((fd=open("my.log",O_RDWR|O_CREAT|O_APPEND,0666))==-1)
        {
            PRINT_ERR("open file error");
        }
        //7.文件描述符重定向
        dup2(fd,0);
        dup2(fd,1);
        dup2(fd,2);
        //8.开启自己的服务
        while(1)
        {
            write(fd,"我是夜猫徐\n",strlen("我是夜猫徐\n"));
            sleep(3);
        }
    }
    else
    {
        //创建孤儿进程需要退出父进程
        printf("父进程退出\n");
        exit(EXIT_SUCCESS);
    }
    return 0;
}

结果展示:
sudo ./a.out执行守护进程
在这里插入图片描述
cd /
在这里插入图片描述
vi my.log
在这里插入图片描述


总结

以上就是今天要讲的内容,本文以详细的代码示例介绍了进程相关函数的使用和守护进程的创建方法以父子进程共用光标的问题。如有错误请海涵可以私信博主,望有所收获。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Linux操作系统】进程详解(下) 的相关文章

  • 每个命令都返回“bash:<命令>:找不到命令...”[关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我刚刚安装了 Scala 并添加了路径gedit bashrc export SCALA HOME home avijit sca
  • 如何在 GNU/Linux 上设置 Subversion (SVN) 服务器 - Ubuntu [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一台运行 Ubuntu 的笔记本电脑 我想将其用作 Subversion 服务器 既让我自己在本地承诺 也让其他人远程承诺 要使其
  • vagrant ssh -c 并在连接关闭后保持后台进程运行

    我正在编写一个脚本来启动和后台流浪机器内的进程 似乎每次脚本结束和 ssh 会话结束时 后台进程也会结束 这是我正在运行的命令 vagrant ssh c cd vagrant src nohup python hello py gt he
  • Linux 上的 RTLD_LOCAL 和dynamic_cast

    我们有一个由应用程序中的一些共享库构成的插件 我们需要在应用程序运行时更新它 出于性能原因 我们在卸载旧插件之前加载并开始使用新插件 并且只有当所有线程都使用旧插件完成后 我们才卸载它 由于新插件和旧插件的库具有相同的符号 我们dlopen
  • 嵌入式linux编写AT命令

    我在向 GSM 模块写入 AT 命令时遇到问题 当我使用 minicom b 115200 D dev ttySP0 term vt100 时它工作完美 但我不知道如何在 C 代码中做同样的事情 我没有收到任何错误 但模块对命令没有反应 有
  • 在 Ubuntu 中找不到 X11/Xlib.h

    我试图在 Linux 上使用 open gl 编写一个相当简单的程序 但在编译时它说 编译拇指 egl 我对 GL 完全陌生 不知道出了什么问题 快速搜索使用 apt search Xlib h 打开 libx11 dev 包 但纯 Ope
  • C - 为什么我无法映射较小(256UL 或更小)的内存?

    请告诉我 为什么我的简单应用程序无法映射较小的内存 而且 为什么有这样一个特定的边界 257UL define MAP SIZE 256UL or below fail define MAP SIZE 257UL ok include
  • dlopen 或 dlclose 未调用信号处理程序

    我在随机时间内收到分段错误 我注册了信号 但发生分段错误时未调用信号处理程序 include
  • 码头无故停止

    我需要经验丰富的码头用户的建议 我在负载均衡器 亚马逊云 后面维护着 2 台 Linux 机器 使用 Jetty 9 0 3 有时我的 Jetty 容器会被 Thread 2 无故关闭 同时地 显示以下日志并且容器无故停止 没有错误 没有例
  • 如何从 Linux 内核模块获取使用计数?

    我对正在开发的内核模块的使用计数有疑问 我想打印它以进行调试 如何从模块代码中获取它 有问题的内核版本 Linux 2 6 32 module refcount http lxr linux no linux v2 6 34 1 inclu
  • 如何设置Java线程的CPU核心亲和力?

    我搜索了以前关于类似主题的帖子 但找不到合适的答案 因此提出这个问题 非常感谢您帮助回答 我知道在 Linux 中通过任务集命令设置进程与特定 CPU 核心的关联性 但我想设置 Java 线程与特定 cpu 核心的亲和力 以便属于同一进程的
  • 在 Docker 容器中以主机用户身份运行

    在我的团队中 我们在进行开发时使用 Docker 容器在本地运行我们的网站应用程序 假设我正在开发 Flask 应用程序app py具有依赖关系requirements txt 工作流程大致如下 I am robin and I am in
  • 如何重命名 .tar.gz 文件而不提取内容并在 UBUNTU 中创建新的 .tar.gz 文件?

    我有一个命令将创建一个新的 tar gz现有文件中的文件 sudo tar zcvf Existing tar gz New tar gz 该命令将创建一个新的New tar gz从现有的文件Existing tar gz file 谁能告
  • 如何从远程 ssh 连接上运行的 tmux(复制模式)复制到本地剪贴板

    我通过 OS X 上的 VirtualBox 运行 Linux 我通过在无头状态下运行虚拟机 然后使用端口转发 sshing 到 Linux 机器来实现这一点 现在 无论复制到我的虚拟机上的剪贴板 我都可以粘贴到我的远程 ssh 会话上 但
  • 运行此处编译的 C 程序会导致在另一台服务器上找不到 GLIBC 库错误 - 是我的错还是他们的错?

    此处编译的 C 程序在我们的 Ubuntu 服务器上运行良好 但是当其他人尝试在他们的特定 Linux 服务器上运行它时 他们会收到以下错误 myprog install lib tls libc so 6 version GLIBC 2
  • 用于读取文件的 Bash 脚本

    不知道为什么最后一行没有从脚本中删除 bin bash FILENAME 1 while read line do cut d f2 echo line done lt FILENAME cat file 1 test 2 test 3 t
  • 计算 TCP 重传次数

    我想知道在LINUX中是否有一种方法可以计算一个流中发生的TCP重传的次数 无论是在客户端还是服务器端 好像netstat s解决了我的目的
  • 裸机交叉编译器输入

    裸机交叉编译器的输入限制是什么 比如它不编译带有指针或 malloc 的程序 或者任何需要比底层硬件更多的东西 以及如何才能找到这些限制 我还想问 我为目标 mips 构建了一个交叉编译器 我需要使用这个交叉编译器创建一个 mips 可执行
  • SMP 上如何处理中断?

    SMP 对称多处理器 多核 机器上如何处理中断 内存管理单元是只有一个还是多个 假设两个线程 A 和 B 运行在不同的内核上 同时 访问页表中不存在的内存页面 在这种情况下 将会出现页面错误 并从内存中引入新页面 将会发生的事件的顺序是什么
  • 为什么默认情况下不启用 arp 忽略/通告 [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我有一个需要经验才能回答的具体问题 为什么 arp ignore arp announce 在 Linux 安装 例如 debian 上默认不启用 有

随机推荐

  • STM32硬件I2C

    以I2C2为例子 硬件I2C不需要我们手动去翻转电平 首先配置I2C xff1a 配置GPIO xff0c 配置复用功能I2C 配置复用开漏 xff0c 使能I2C I2C起始条件函数 64 param I2Cx where x can b
  • 最简单的 DRM 应用 & drm设备不工作

    https zhuanlan zhihu com p 341895843 https zhuanlan zhihu com p 75321245 编写最简单的 DRM 应用 主程序 xff1a int main int argc char
  • spi通信

    特点 常规四线通信方式 一根片选线 xff0c 一根时钟线 xff0c 两根数据线 xff1a 一根是主进从出线 xff0c 一根主出从入线 同步 xff0c 全双工 xff0c 通信方式 和谁通信就将谁的片选线拉低 xff0c 每增加一个
  • FreeRtos任务通信之消息队列

    入队阻塞 xff1a 往队列写数据时 xff0c 队列满时的阻塞 当阻塞结束时 xff0c 优先级最高的任务优先进入就绪态 xff0c 同 优先级时 xff0c 阻塞时间最长的进入就绪态 出队阻塞 xff1a 读队列时 xff0c 队列为空
  • STM32F103C8T6 ADC功能

    12位逐次逼近型ADC 1us转换时间 输入电压0 3 3v和转化范围0 2 12 1 xff08 0 4095 xff09 成线性关系 2个ADC资源 xff0c ADC1和ADC2 xff0c 10个外部通道 有两种转换单元组 xff1
  • stm32串口实验

    目录 xff08 一 xff09 STM32 串口简介 二 软件设计 xff08 三 xff09 效果 xff1a 1 实现功能 xff1a STM32 通过串口和上位机的对话 xff0c STM32 在收到上位机发过来的字符串后 xff0
  • 基于stm32的GPS解析数据

    目录 1 GPS模块 2 GPS发送的数据格式 3 软件设计 3 1配置好串口 3 2然后写串口中断函数 效果 1 GPS模块 2 GPS发送的数据格式 GPRMC lt 1 gt lt 2 gt lt 3 gt lt 4 gt lt 5
  • 大疆遥控控制M3508电机二(基于HAL库)

    接上一篇文章 xff0c 话不多说直接开始 一 打开我们创建的工程文件 xff0c 先就建立一个文件夹用来存放我们写的子文件 xff08 不建立也行 xff09 xff0c 然后建立pid h xff0c pid c存入我们建立的文件夹中
  • aruco_ros 在相机图像中显示的坐标轴姿态与TF发布的姿态不一致 解决方法

    aruco ros 在相机图像中显示的坐标轴姿态与TF发布的姿态不一致 解决方法 运行环境问题描述解决方案 运行环境 系统版本 xff1a Ubuntu 16 04 ROS版本 xff1a Kinetic 问题描述 在进行手眼标定过程中 x
  • 安装vscode的时候没有勾选快捷方式用vscode打开文件,如何用vscode快速打开文件或者文件夹

    1 需要在注册表里面添加内容可以实现 xff0c 下面有一种简单的方式来完成这个操作 2 需要在电脑桌面新建一个Open File With VS code reg 文件然后用打开文件 xff0c 将以下代码复制 Windows Regis
  • C语言学习笔记->const和define区别

    1 define 是预编译指令 xff0c 而const 是普通变量的定义 define定义的宏是在预处理阶段展开的 xff0c 而const定义的只读变量在编译运行中使用 2 const定义的是变量 xff0c 而define定义的是常量
  • 基于栈、寄存器的优缺点

    基于栈的优点 xff1a 对硬件的依赖不高 xff0c 跨平台性 缺点 xff1a 使用的指令集高基于寄存器的优点 xff1a 相对于栈来说 xff0c 寄存器的性能高 xff0c 使用的指令集少 Java代码执行流程 xff1a java
  • Makefile文件的编写(实例详解)

    1 什么是Makefile xff1f 一个工程中的源文件不计其数 xff0c 其按类型 功能 模块分别放在若干个目录中 xff0c Makefile定义了一系列的规则来指定哪些文件需要先编译 xff0c 哪些文件需要后编译 xff0c 哪
  • 用C语言实现万年历的代码及思路(详细教程)

    万年历程序要求 xff1a 1 当选择1的时候 xff0c 输入年 xff0c 打印输入的这一年12月的日历 2 当选择2的时候 xff0c 输入年 月 xff0c 打印输入这一年这一月的日历 实现效果 xff1a 选择1时 span cl
  • 有符号数和无符号数参与运算时的问题

    陷阱题目 xff1a 下面的代码输出是 xff08 xff09 span class token macro property span class token directive hash span span class token di
  • 【Linux网络编程】基于UDP实现多人聊天室

    文章目录 一 UDP的概念1 1 UDP1 2 UDP特点 二 采用UDP实现多人聊天室原因三 多人聊天室项目功能四 实现多人聊天室项目流程分析4 1 前期准备4 1 1 定义结构体4 1 2 定义链表 4 2 多人聊天室服务器4 2 1
  • 【C++】C向C++的知识过度(上)

    文章目录 一 C与C 43 43 的区别1 1 C是面向过程的1 2 C 43 43 是面向对象的1 3 编译器的区别 二 C与C 43 43 默认代码的不同三 命名空间3 1 关键字 96 namespace 96 去定义自己的名字空间
  • 【C++】四种类型转换 | C++异常处理机制 | C++11新特性之右值引用和移动构造

    文章目录 一 C 43 43 中的四种类型转换1 1 静态类型转换1 1 1 C 43 43 中内置类型的转换1 1 2 C 43 43 中的有继承关系存在的场景下的类型强转 1 2 动态类型转换1 3 常类型转换1 4 解释类型转换 二
  • 【Linux操作系统】进程详解(上)

    文章目录 一 进程的定义二 进程的特征三 进程的组成及其作用四 进程控制块4 1 进程控制块定义4 2 task struct的内容 五 进程与程序的区别六 进程与线程的区别七 进程的种类八 PID8 1 PID定义8 2 特殊PID的进程
  • 【Linux操作系统】进程详解(下)

    文章目录 前言一 父子进程共用光标问题1 1 验证1 2 规避共用光标问题使用多进程拷贝同一个文件 二 进程相关函数2 1 getpid getppid函数2 2 exit exit函数2 3 wait waitpid函数 三 守护进程3