TLPI-Chapter 6 进程

Linux/UNIX系统编程手册的支持代码 Linux/UNIX系统编程手册的支持代码,即tlpi_hdr.h,error_functions.h,get_num.c等在全文工程会用到的附带代码,以及第8.2部分/etc/passwd部分代码。 立即下载

每个进程都有一个唯一进程标识号(process ID),并保存有对其父进程号的记录。
进程的虚拟内存逻辑上被划分为许多段:文本段、数据段、栈和堆。
栈由一系列帧组成,随函数调用而增长,随函数返回而减,每个帧都包含有函数局部变量、函数实参以及单个函数调用的调用链接信息。
程序调用时命令行参数通过argc argv参数提供给main()函数。通常argv[0]包含调用程序的名称。
每个进程都会获得其父进程环境列表的一个副本,即一组”名称-值“的键值对。全局变量environ和各种库函数允许进程访问和修改其环境列表中的变量。
setjmp()函数和longjmp()函数提供了从函数甲执行非局部跳转到函数乙的方法。在调用这些函数时,为避免编译器优化所引发的问题,应使用volatile修饰符声明变量。非局部跳转会使程序难以阅读和维护,应尽量避免使用。
进程是一个可执行程序的实例。一个程序可以创建很多进程。
进程是由内核定义的抽象实体,内核为此实体分配执行程序所需的系统资源。
从内核的角度来看,进程是由用户内存空间和内核数据结构组成的。程序的代码和代码中的变量存放在用户内存空间,内核数据结构用于维护进程状态信息。
对于每个进程都有一个唯一的进程号(进程ID)(正数),用来标识系统中的某个程序。
系统调用getpid()返回调用进程的进程号。
系统调用getppid()可以检索到父进程的进程号。
使用命令pstree可以查看进程树。
如果子进程的父进程终止,则子进程就会变成孤儿,Init进程随即收养该进程,子进程后续对getppid()调用将返回进程号1.
在Linux系统中可以查看/proc/进程PID/status中PPid字段获知该进程的父进程。
本章中介绍的进程内存布局可以参考文章C内存布局,本书48.5节会更详细介绍进程内存布局。

#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>

char globBuf[65536];            /* Uninitialized data segment */
int primes[] = { 2, 3, 5, 7 };  /* Initialized data segment */
mem_se
static int
square(int x)                   /* Allocated in frame for square() */
{
    int result;                 /* Allocated in frame for square() */

    result = x * x;
    return result;              /* Return value passed via register */
}

static void
doCalc(int val)                 /* Allocated in frame for doCalc() */
{
    printf("The square of %d is %d\n", val, square(val));

    if (val < 1000) {
        int t;                  /* Allocated in frame for doCalc() */

        t = val * val * val;
        printf("The cube of %d is %d\n", val, t);
    }
}

int
main(int argc, char *argv[])    /* Allocated in frame for main() */
{
    static int key = 9973;      /* Initialized data segment */
    static char mbuf[10240000]; /* Uninitialized data segment */
    char *p;                    /* Allocated in frame for main() */

    p = malloc(1024);           /* Points to memory in heap segment */

    doCalc(key);

    exit(EXIT_SUCCESS);
}

可以通过将上述代码中的内容只保留main函数其余注释掉之后编译,size 查看结构,然后在取消注释之后,逐步查看size的不同,进而确定该类型变量在内存中的布局.

环境列表

每个进程都有与自己相关的环境列表。
每条记录的形式为name=value;
新进程创建时会继承父进程的环境副本(原始的进程间通信方式。
可以通过printenv输出当前的环境列表:
在linux系统中通过查看/proc/进程PID/environ文件可以查看相应的环境列表。

char *getenv(const char *name);

对于存在name的环境变量就返回对应的value的指针,如果不存在就返回NULL

int putenv(char *string);

将name=value形式的字符串添加到当前的环境列表。成功返回0,失败返回非0值。
putenv是将environ变量的某个元素指向string指向的位置,并不是指向string指向字符串的副本。所以如果修改string指向的内容,环境变量也会改变,因此string指向后来不能是自动变量。
当string里不包含等号的时候,将会在环境列表移除string命名的环境变量。

int setenv(const char *name, const char *value, int overwrite);

name,value与name=value对应,overwrite决定时候改变环境。如果以name标识的变量存在环境里而且overwrite为0,就不改变环境;否则如果overwrite不为0就总是改变环境。
成功返回0, 失败返回-1
不同与putenv,setenv是分配一块内存缓冲区,将name和value指向的字符串复制到缓冲区里。

int unsetenv(const char *name);

移除name标识的变量
成功调用返回0,失败返回-1。

int clearenv(void);

成功调用返回0,失败返回非0值。
setenv和clearenv会导致内存泄露:setenv分配了一块内存缓冲区,但是clearenv没有释放这个缓冲区。
例子:

#define _GNU_SOURCE     /* Get various declarations from <stdlib.h> */
#include <stdlib.h>
#include "tlpi_hdr.h"

extern char **environ;

int
main(int argc, char *argv[])
{
    int j;
    char **ep;

    clearenv();         /* Erase entire environment */

    /* Add any definitions specified on command line to environment */

    for (j = 1; j < argc; j++)
        if (putenv(argv[j]) != 0)
            errExit("putenv: %s", argv[j]);

    /* Add a definition for GREET if one does not already exist */

    if (setenv("GREET", "Hello world", 0) == -1)
        errExit("setenv");

    /* Remove any existing definition of BYE */

    unsetenv("BYE");

    /* Display current environment */

    for (ep = environ; *ep != NULL; ep++)
        puts(*ep);

    exit(EXIT_SUCCESS);
}

命令行参数相关讲解参考文章C语言命令行参数

执行非局部跳转setjmp()和longjmp()

setjmp()函数和longjmp()函数提供了从函数甲执行非局部跳转到函数乙的方式。
示例代码:

#include <setjmp.h>
#include "tlpi_hdr.h"

static jmp_buf env;

static void
f2(void)
{
    longjmp(env, 2);
}

static void
f1(int argc)
{
    if (argc == 1)
        longjmp(env, 1);
    f2();
}

int
main(int argc, char *argv[])
{
    switch (setjmp(env)) {
    case 0:     /* This is the return after the initial setjmp() */
        printf("Calling f1() after initial setjmp()\n");
        f1(argc);               /* Never returns... */
        break;                  /* ... but this is good form */

    case 1:
        printf("We jumped back from f1()\n");
        break;

    case 2:
        printf("We jumped back from f2()\n");
        break;
    }

    exit(EXIT_SUCCESS);
}

代码解析:
上面代码保存为longjmp.c,运行./longjmp此时argc为1,如果我输入./longjmp x argc不为1,上述代码setjmp只有在第一次执行时返回0,然后下次执行时通过longjmp跳转过来,通过longjmp设置的值就是setjmp返回的值,本例中f1中返回1,f2中返回2.

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>

static jmp_buf env;

static void
doJump(int nvar, int rvar, int vvar)
{
    printf("Inside doJump(): nvar=%d rvar=%d vvar=%d\n", nvar, rvar, vvar);
    longjmp(env, 1);
}

int
main(int argc, char *argv[])
{
     int nvar;
     register int rvar;          /* Allocated in register if possible */
    volatile int vvar;          /* See text */

    nvar = 111;
    rvar = 222;
    vvar = 333;

    if (setjmp(env) == 0) {     /* Code executed after setjmp() */
        nvar = 777;
        rvar = 888;
        vvar = 999;
        doJump(nvar, rvar, vvar);

    } else {                    /* Code executed after longjmp() */

        printf("After longjmp(): nvar=%d rvar=%d vvar=%d\n", nvar, rvar, vvar);
    }

    exit(EXIT_SUCCESS);
}

代码讲解:
gcc -o setjmp_vars setjmp_vars.c
gcc -O -o setjmp_vars setjmp_vars.c
-O选项是开启编译器优化,上述例子中如果不将局部变量定义为volatile的话在调用setjmp()的函数中会存在问题。所以为避免编译器优化所引发的问题,应使用volatile修饰符声明变量。

《unix环境高级编程》里面的outhdr.h 《unix环境高级编程》里面的几乎所有的程序都用到的ourhdr.h,亲测可以使用,需哟啊的下载 立即下载

相关推荐

群晖NAS从入门到精通的所有帖子汇总,只要这一篇就够了

本站陆陆续续的转载、原创帖子也有十几二十篇了,从不同的角度对群晖NAS的各种骚操作都有深入的讲解,虽然很多文章都不是讲的很深入,但是针对小白入门已经是足够了,希望对小白来说是一个入门,群晖NAS的大佬们勿喷,哪里写的不对的,请随时留言西安SEO优化站长一定在第一时间纠正修改。

西安SEO优化网站资源 8万+

tlpi_hdr.h头文件使用及设置

使用的头文件,主要如下: ename.c.inc error_functions.h get_num.h tlpi_hdr.h 其中ename.c.inc文件定义了一个字符串数组,用于对应错误码的名称。 error_functions.h文件声明了本书自定义的错误处理函数。 get_num.h文件声明了本书自定义的数值提取函数。 tlpi_hdr.h文件则包含了后续需用到的系统调用头文件。 将头文件复制到默认的编译器寻找目录下,并将实现打包成静态库,然后使用别名来默认链接静态库。 具体操作如下: 第一步.

liao__ran的博客 1957

【ChatGPT实战案例】ChatGPT如何帮助产品经理高效工作?

1. 产品经理主要工作方向, 2. 具体工作中,向ChatGPT提问参考

weixin_62909516的博客 1900

LinuxUNIX系统编程手册——(四)文件IO:通用的IO模型

所有执行 I/O 操作的系统调用都以文件描述符,一个非负整数(通常是小整数),来指代打开的文件。文件描述符用以表示所有类型的已打开文件,包括管道(pipe)、FIFO、socket、终端、设备和普通文件。大多数程序都期望能够使用 3 种标准的文件描述符,见下表。文件描述符用途POSIX名称stdio流0标准输入stdin1标准输出stdout2标准错误stderr。

hello_world0_0的博客 1152

保姆级教程:手把手带你复现APFNet论文的RGBT目标跟踪模型(附完整代码与数据集配置)

本文提供了一份详细的APFNet论文复现指南,涵盖从环境搭建到模型测试的全流程。通过解析多模态融合模块和渐进式训练流程,帮助读者高效完成RGBT目标跟踪模型的复现工作,特别针对训练和测试中的常见问题提供实用解决方案。

weixin_29056781的博客 343

完美解决LBP2900打印机安装驱动提示无法识别USB及连接错误等问题(附Win11全新安装支持及卸载方案)

LBP2900打印机虽然经典老旧,但在Win11上依然可以完美使用!许多网上教程都无视安装失败后的问题,在此分享一种全新、100%有效的方法来解决驱动连接错误和无法识别USB设备的问题。无论是新安装还是卸载重装,这个方法都适用。本文整合了通用驱动包,支持Win2000到Win11系统,操作简单,轻松摆脱安装困扰,享受无忧打印体验!

心开始の未来~的博客 2万+

TLPI-Chapter 4文件IO

所有执行I/O操作的系统调用都以文件描述符(一个非负整数)来指代打开的文件。文件描述符用以表示所有类型的已打开文件,包括管道、FIFO、socket、终端、设备、普通文件。它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。每个进程,文件描述符都自成一套。 三种标准的文件描述符: 0 标准输入 1 标准

尘世中迷途小书童 506

解决anaconda占用C盘空间过多问题

anaconda就算安装在其他盘,默认会把索引、锁定文件、压缩包等都放到系统盘(C盘),我用了两年,占用30GB。 1. 卸载不用的虚拟环境 查看已安装的虚拟环境 conda env list 卸载不用的、过期的虚拟环境 conda remove -n (要卸载的环境的名字) --all 2. 删除索引缓存、锁定文件、未使用过的包和tar包 conda clean -a 清理完之后,删除了15GB,还剩15GB,舒服了 ...

沉迷单车的追风少年 3万+

4. 文件I/O:通用I/O模型

描述了基本文件I/O的概念。讲解了open, read, write, close, lseek 以及 ioctl基本函数

u010933311的博客 631

把个人化的 SQVI 报表变成可维护、可共享、可传输的 ABAP Query:从定位来源到转换落地的完整路线图

本文针对SAP系统中业务用户常用但难以维护的SQVI临时报表问题,提供了一套完整的解决方案。文章首先区分了SQVI(个人临时报表)和ABAP Query(团队可维护报表)的关键差异,重点介绍了如何通过函数模块RSAQ_DECODE_REPORT_NAME反查报表来源。对于SQVI报表,详细说明了定位创建人和转换为团队可维护的ABAP Query的具体步骤,包括Query Area切换、转换操作和后续维护方法。最后总结了常见问题的解决方案,如字段调整、口径固化和生成程序名反查等,为现场实施提供了可直接操作的完

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 302

SAP_FICO模块-资产减值功能对折旧和残值的影响

SAP_FICO模块-资产减值操作对资产历史折旧以及后续折旧的影响,包括减值操作的配置前提

风沙的博客 2805

板凳--------第20章-信号:基本概念1

信号是事件发生时对进程的通知机制,软件中断。信号与硬件中断的相似之处在于打断了程序执行的正常流程,无法预测信号到达的精确时间。一个具有权限的进程能够向另一进程发送信号。信号,一种同步技术,甚至是进程间通信( IPC)的原始形式。进程也可以向自身发送信号。然而,发往进程的诸多信号,通常都是源于内核。引发内核为进程产生信号的各类事件如下。1.硬件发生异常,即硬件检测到一个错误条件并通知内核,随即再由内核发送相应信号给相关进程。2.用户键入了能够产生信号的终端特殊字符。

fengye207161的博客 1307

【100%通过率】华为OD机试真题 Python 实现【字符串重新排列】【2022.11 Q4新题】

给定一个字符串s,s包括以空格分隔的若干个单词,请对s进行如下处理后输出: 1、单词内部调整:对每个单词字母重新按字典序排序 2、单词间顺序调整: 1)统计每个单词出现的次数,并按次数降序排列 2)次数相同,按单词长度升序排列 3)次数和单词长度均相同,按字典升序排列 请输出处理后的字符串,每个单词以一个空格分隔。

MISAYAONE的博客 7982

TLPI-Chapter 9 进程凭证

这一章开始看的有点懵,在网上搜索到一篇文章有助于理解链接地址Set-User-ID 1.每个进程都有一套用数字表示的用户ID和组ID。具体有实际用户ID(real user ID), 实际组ID(real group ID),有效用户ID(effective user ID),有效组ID(effective group ID),保存的set-user-ID和set-group-ID,文件系统用户I

尘世中迷途小书童 763

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

TLPI-Chapter 20 信号

基本概念信号是事件发生时对进程的通知机制。有时也称为软件中断,信号与硬件中断相似之处在于打断了程序执行的正常流程,大多数情况下,无法预测信号到达的精确时间。 一个具有合适权限的进程能够向另一进程发送信号,信号的这一用法可作为一种同步技术,甚至是进程通信IPC的原始形式。进程也可以向自身发送信号。然而发往进程的诸多信号,通常都是源于内核。 引发内核为进程产生信号的各类事件如下: 硬件发生异常:硬

尘世中迷途小书童 477

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

TLPI-Chapter 12系统和进程信息

“The /proc file system exposes a range of kernel information to application programs. Each /proc/PID subdirectory contains files and subdirectories that provide information about the process whose ID m

尘世中迷途小书童 304

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

TLPI-Chapter 5深入探究文件

原子操作 UNIX/Linux系统编程手册第5章深入探究文件I/O,所有的系统调用都是以原子操作方式执行。 内核保证系统调用中的所有步骤会作为一个独立操作而一次性加以执行,期间不会为其它进程或线程中断. 下面的代码中open并未使用O_EXCL标志,在程序中为了对执行该程序的进程加以区分,打印了进程号。 /****************************************

尘世中迷途小书童 356

TLPI-Chapter 10 时间

日历时间Calendat TimeUNIX系统内部对时间的表示均是以自1970年1月1日的零点以来的秒数来度量。日历时间存储与类型time_t的变量中,此类型是由SUSv3定义的整数类型。 系统调用gettimeofday(),可于tv指向的缓冲区中返回日历时间。#include <sys/time.h> int gettimeofday(struct timeval *tv, struct ti

尘世中迷途小书童 360

TLPI-Chapter 3系统编程概念

第三章内容概念讲的其实相对好理解,主要有如下几点: 系统调用是可控的内核入口,进程可以请求内核以自己的名义去执行某些动作,这就用到了系统调用,讲处理器从用户态切换到内核态。 在书中作者用到一个例子X86-32为例,按事件发生顺序: 1.应用程序通过外壳(wapper)函数,发起系统调用 2.参数入栈,传入外壳函数。 3.外壳函数将参数置入特定寄存器(包括系统调用编号) 4执行中断机器指令

尘世中迷途小书童 294

TLPI-Chapter 11系统限制和选项

关于系统限制C语言标准和SUSv3提供了两种方法: 1.在编译程序时能够获得一些限制和选项。 2.一些限制在程序运行时可能会发生变化。对此SUSv3定义了3个函数sysconf() pathconf()和fpathconf(),供应用程序调用以检查系统实现的限制和选项。 SUSv3将其规定的限制归为三类: 运行时恒定值 路径名变量值 运行时可增加值 在shell中,可以使用getco

尘世中迷途小书童 849

TLPI-Chapter 13文件I/O缓冲

函数:void *memalign(size_t alignment, size_t size); The obsolete function memalign() allocates size bytes and returns a pointer to the allocated memory. The memory address will be a multiple of alignment

尘世中迷途小书童 374

c语言中pi怎么写头文件,tlpi_hdr.h头文件的使用以及配置

本章介绍系统编程的基础概念和一些后续章节用到的函数及头文件,并说明了可移植性问题。系统调用是受控的内核入口,通过系统调用,进程可以请求内核以自己的名义去执行某些动作,比如创建子进程,执行I/O操作,进行进程间的通信等。系统调用与C语言的函数调用类似。但是系统调用的过程比C语言函数调用复杂,开销也大得多。Linux 的系统调用通过 int 0x80 实现,用系统调用号来区分入口函数。操作系统实现系统...

weixin_35795512的博客 958

C 语言套接字UDP机制实现

说明:此示例仅用于展示UDP的实现方法,仅供参考学习,没有实际使用功效。另外此实现分为服务器与客户机两部分代码,开发环境为GNU glibc_2.24,运行环境为Debian 9(linux)。 服务器端代码为: #include<tlpi_hdr.h> /*此头文件具体包含内容在本文最末尾列出*/ int main() { int sock_no; int return_s...

JmanCryTears的博客 367

linux下C通过系统调用进行基本IO操作

一.Linux下通过系统调用对普通文本文件进行I/O操作步骤: 调用open()获得一个文件描述符 利用获得的文件描述符作为read() 和write()的一个参数,进行I/O操作。 使用close()释放文件描述符及其相关资源。 文件描述符:一个非负整数(无符号整数),用于引用在内核中打开的文件。打开或创建一个文件时,内核返回一个文件描述符。读写一个文件时利用open、creat函数返回的文件描述

Try的博客 1787

linux系统编程手册错误,Linux系统编程手册 学习笔记(二)

第四章:文件I/O:通用的I/O模型在该章节中讨论的文件描述符的概念。其中包括:打开文件,关闭文件,从文件中读取数据和向文件中写数据。概述所有执行I/O操作的系统调用都以文件描述符(一个非负整数(通常是比较小的整数))来指代打开的文件。文件描述符用以表示所有类型的已打开文件,包括管道(pipe)、FIFO、socket、终端、设备和普通文件。下面介绍执行I/O操作的4个主要系统调用:open:fd...

weixin_39652658的博客 245
上一篇: Markdown基本语法
下一篇: strtol函数
52coder
博客等级 码龄17年 87粉丝 128原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值