多人猜数游戏

一. 多进程的调试

1. 使用vscode的gdb attach调试

  • 调试注意

      1. 调试时报错解决方法click here
      1. 多进程调试时,要尽量在程序需要停止的地方加上getchar(),同时打上断点,双保险保证程序能够在指定的地方停止。
      1. 擅用fflush和getch()
          1. 使用fflush(stdout)
            printf函数是按行刷新的缓冲区的,如果printf()中不加\n,会导致不能立即输出的情况,而是需要等到程序结束自动,清空缓冲区时才能输出。此时我们可以使用fflush(stdout)提前清空缓冲区。
          1. 使用fflush(stdin)
            使用fflush(stdin)放到getchar(),scanf()等输入函数后面,来避免输入缓冲区异常

二. 对管道文件的操作

1. 查看管道文件的状态

管道文件虽然不能直接查看大小,但是我们可以通过lsof | grep 文件名,来查看管道文件是否打开 (但注意管道文件打开不等于就能够进行通讯,看第二点),以及被以什么方式打开(读或写)。

2.write,read函数和管道文件

  1. 管道文件能够通信的条件是,管道打开,且write和read函数在管道两端同时监听,即是write在写入管道的同时管道另一端必须要正在read。
    wirte返回值为0时原因是,(1)read没有正在监听(2)写入数据为0字节
    read返回值为0时原因是,(1)write没有正在监听

    没有监听的原因可能是(1)有getchar()等函数卡住了进程导致write和read函数没有执行。(2)服务器或客户端挂掉(3)也可能是管道异常关闭。

    对于管道异常关闭我们使用,以下代码检测

sigpipe_handler函数模板
void sigpipe_handler(int signum) {
    printf ("SIGPIPE received\n");
}

sigpipe_handler的目的是当管道出现关闭,signal会捕获到SIGPIPE,信号,注册
sigpipe_handler函数并执行。下面的判断语句是检测是否成功注册sigpipe_handler函数

    if (signal(SIGPIPE, sigpipe_handler) == SIG_ERR) {
        std::cerr << "Failed to register SIGPIPE handler\n";
        return 1;
    }
    
  1. 因为一个管道可以有多个读端和写端,所以必须要管道另一端确实没有任何读入 端时,write才会返回0。同时signal函数接受到pipe broken信号
    反之同理需要确实没有任何输入端,read才会返回0。同时signal函数接受到pipe broken信号

  2. open管道的条件是读端和写端被同时打开,如果只是打开open一端,则会卡在open函数无法继续,必须两端都被打开open函数能执行

三. 犯错

犯错:
又是括号惹的祸,记得之前写嵌入式小车时因为if括号问题导致优先级错误所以一直卡住。这次的猜数游戏也是if括号的问题导致优先级错误。

(重点) 四. 如何调试fork产生的父子进程

使用gdb attach加kill挂起/开始进程,可以调试父子进程

问题1:在从1进程切换到2进程时,如果我们在1进程后的某一个位置打断点,试图想当我们调试2进程时让1进程停到断点这是不可行的,当切换进程后进程1会自动执行而不会在断点停下。

解决方法:当我们在切换进程之前先使用kill -STOP <进程号>挂起当前进程,然后切换到另一进程调试。调试完后用同样的方法回到当前进程,然后使用kill -CONT <进程号>开始当前进程但注意此时要在后面某个位置打断点,以便开始进程后能够在断点处停下来。同时,当我们切回进程的时候程序会报错signal STOP这是因为我们发出的暂停信号,当启动时又会报错signal continue,这是因为我们发出的开始信号,但这不影响程序执行

五. 重启进程

1. 我们重启进程可以使用fork() + exec()

(1)当路径为可执行文件时

void restart1(){
    printf("try restarting\n");
    pid_t pid = fork();
    if(pid == 0){
        char self_path[1024];
        char *argv[] = {"/home/guoziyi/Desktop/ALL/guess/build/client1", NULL};

        printf("current exe path is: %s\n", argv[0]);
        if(execv(argv[0], argv) == -1){
            perror("evecv error");
            exit(1);
        }
        printf("restart successfully\n");
    }
}

(2)当路径为可执行文件的链接时我们使用readlink,注意reaklink返回值为真实路径的长度

void restart(){
     printf("try restarting\n");
     pid_t pid = fork();
     if(pid == 0){
		 char *argv[] = {"/home/guoziyi/Desktop/ALL/guess/build/client1", NULL};
		  path_length = readlink("/home/guoziyi/Desktop/ALL/guess/build/client1", self_path, sizeof(self_path) - 1);
		    self_path[path_length] = '\0';
		
		    printf("current exe path is: %s\n", self_path);
		    if(execv(self_path, argv) == -1){
		        perror("evecv error");
		        exit(1);
		    }
		    printf("restart successfully");
	    }
}

(3)在重启进程,并在新的终端打开

void restart1(){
    printf("try restarting\n");
    pid_t pid = fork();
    if(pid == 0){
        char self_path[1024];
        char *argv[] = {"/usr/bin/gnome-terminal", "--", "/home/guoziyi/Desktop/ALL/guess/build/client1", NULL};
        printf("current exe path is: %s\n", argv[2]);
        if(execv(argv[0], argv) == -1){
            perror("evecv error");
            exit(1);
        }
        printf("restart successfully\n");
    }
}

2.为什么execv(self_path, argv) 的第二个参数必须至少有一个,即argv[0]为什么不能为空?

当我们打开一个进程的时候时候,肯定会从main函数开始执行。我们知道
int main(int argc, int *argv[]),中的argv[0]默认传递的就是可执行文件的路径,所以我们调用execv(self_path, argv)时,至少argv必须有一个元素,且为可执行文件的路径

五. 使用vscode和gdb联调

在启动vscode调试之后,可以再在调试控制台使用gdb命令辅助调试。

  1. 查看所用栈帧
    -exec bt
  2. 查看指定栈帧
    -exec f 栈帧号
  3. 打印变量类型和大小
    -exec ptype 变量名
    参考

六. 如何获取调试失败的信息

我们可以通过调试core文件,来找到失败原因
参考

七. VS,clion调试

在对Windows应用程序附加到进程调试最好使用vs
参考

八. vscode找不到头文件或c++库

1.查看库文件目录

Windows:一般使用mingw_x64,所以在mingw_x64目录进行寻找
linux:一般使用gcc和g++,使用 **echo | g++ -v -x c++ -E -**来查看库文件目录

2.导入库文件目录

(1)我们可以按照提示配置为在库文件所在文件夹下递归搜索

(2)在vscode中我们按照下“Shift+Ctrl+p” 输入: C++Configurations,选择UI界面或使用c_cpp_properties.json文件导入头文件目录即可
(3)如果还不行,就禁用重启所有的c/c++扩展

3. 如果使用c++的头文件一定要把.c改为.cpp

相关推荐

  1. 游戏

    2024-07-17 17:42:04       27 阅读
  2. Python写游戏

    2024-07-17 17:42:04       32 阅读
  3. 【Rust入门】游戏

    2024-07-17 17:42:04       25 阅读
  4. Python 代码实现游戏

    2024-07-17 17:42:04       28 阅读
  5. 有趣的游戏C/C++

    2024-07-17 17:42:04       26 阅读
  6. Rust 练手小项目:游戏

    2024-07-17 17:42:04       30 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-17 17:42:04       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-17 17:42:04       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-17 17:42:04       58 阅读
  4. Python语言-面向对象

    2024-07-17 17:42:04       69 阅读

热门阅读

  1. 终止Promise的执行

    2024-07-17 17:42:04       20 阅读
  2. zookeeper相关总结

    2024-07-17 17:42:04       17 阅读
  3. MySQL5.7社区版本在CentOS7系统上的安装

    2024-07-17 17:42:04       19 阅读
  4. Android 自定义Drawable实现跑马灯效果

    2024-07-17 17:42:04       22 阅读
  5. Dubbo的RPC协议有哪些独特之处

    2024-07-17 17:42:04       19 阅读
  6. vue中缩放比的使用

    2024-07-17 17:42:04       20 阅读
  7. Linux指令&&ros学习&&python深度学习&&bug学习笔记

    2024-07-17 17:42:04       18 阅读
  8. 中文科技核心论文发表

    2024-07-17 17:42:04       19 阅读
  9. MPS 后端

    2024-07-17 17:42:04       23 阅读