嵌入式Linux应用程序开发——期末复习重点

目录

  • 前言 题型分布
  • 第1章 搭建嵌入式Linux开发环境
    • 1.1 构建嵌入式linux交叉开发环境
    • 1.2 Bootloader
  • 第2章 Linux系统调用及用户编程接口(API)
    • 2.1.2 用户编程接口(API)
    • 2.2 Linux 文件I/O系统概述
    • 2.3 底层文件 I/O 操作
    • 2.3.2 文件锁
    • 2.3.3 多路复用
    • 2.4 嵌入式Linux串口应用编程
    • 2.5 标准 I/O 编程
  • 第3章 嵌入式 Linux 多任务编程
    • 3.1.2 任务
    • 3.1.3 线程
    • 3.3.2 Linux 守护进程
    • 3.2.3 Linux僵尸进程
  • 第4章 嵌入式 Linux 进程间通信
    • 管道读写示例
    • 4.3 信号通信
    • 4.4.1 信号概述
  • 第5章 嵌入式 Linux 多线程编程
    • 线程属性
  • 第6章 嵌入式 Linux 网络编程

前言 题型分布

  • 选择题
  • 填空题
  • 简答题
  • 程序阅读题
  • 编程大题

第1章 搭建嵌入式Linux开发环境

1.1 构建嵌入式linux交叉开发环境

构建一个Linux系统,需要考虑一下几点:

  • 选择Linux发行版
  • 熟悉开发环境和工具
  • 熟悉Linux内核
  • 熟悉目标板引导方式
  • 熟悉Linux根文件系统
  • 理解Linux内存模型
  • 理解Linux调度机制与进程和线程模型

要搭建嵌入式______环境

  • 交叉编译

1.2 Bootloader

什么是Bootloader?

  • Bootloader 是在操作系统运行之前执行的一小段程序。通过它可以初始化硬件设备、建立内存空间的映像表,从而建立适当的软、硬件环境,为最终调用操作系统内核做好准备。
  • 对于嵌入式系统,Bootloader 是基于特定平台实现的,因此,不可能为所有的嵌入式系统都建立一个通用的Bootloader ,不同的处理器架构有不同的Bootloader 。Bootloader 不但依赖于CPU的体系结构,而且依赖于嵌入式系统板级设备的配置。对于两块不同的嵌入式主板而言,即使他们使用同一种处理器,要想运行在一块主板上的 Bootloader 程序也能运行在另一块主板上,一般需要修改 Bootloader 的源程序

U-Boot的编译与使用

  • 考察方式未知,课本P12,看不懂

U-Boot常用命令

  • 考察方式未知,课本P16,看不懂

第2章 Linux系统调用及用户编程接口(API)

2.1.2 用户编程接口(API)

什么是API?

  • 课本P39,看不懂

2.2 Linux 文件I/O系统概述

虚拟文件系统(VFS)的概念

  • 课本P40

通常,一个进程启动时,都要打开三个文件:______ ,______ ,______.

  • 标准输入
  • 标准输出
  • 标准出错处理

这三个文件对应的文件描述符分别为0,1,2,也就是宏替换STDIN_FILENO,STDOUT_FILENO和STDERR_FILENO.

2.3 底层文件 I/O 操作

2.3.1 基本文件操作
课本P42

  • open()
  • close()
  • read()
  • write()
  • lseek()

copy_file.c
拷贝好代码,使用管理员身份创建dest_file和src_file两个文件,在src_file中输入随便一些字符串,运行a.out后会把src中内容复制到dest中:

/* copy_file.c */
#include 
#include 
#include 
#include 
#include 
#include 

#define	BUFFER_SIZE	1024	/* 每次读写缓存大小,影响运行效率 */
#define	SRC_FILE_NAME	"src_file"	/* 源文件名 */
#define	DEST_FILE_NAME	"dest_file"	/* 目标文件名 */
#define	OFFSET	10240	/* 复制的数据大小 */

int main()
{
	int src_file, dest_file;
	unsigned char buff[BUFFER_SIZE];
	int real_read_len;

	/* 以只读方式打开源文件 */
	src_file = open(SRC_FILE_NAME, O_RDONLY);

	/* 以只写方式打开目标文件,若此文件不存在则创建该文件,访问权限值为644 */
	dest_file = open(DEST_FILE_NAME, O_WRONLY | O_CREAT, 
		S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
	if(src_file < 0 || dest_file < 0)
	{
		printf("Open file error\n");
		exit(1);
	}

	/* 将源文件的读写指针移到最后10KB的起始位置 */
	lseek(src_file, -OFFSET, SEEK_END);

	/* 读取源文件的最后10KB数据并写到目标文件中,每次读写1KB */
	while((real_read_len = read(src_file, buff, sizeof(buff))) > 0)
	{
		write(dest_file, buff, real_read_len);
	}

	close(dest_file);
	close(src_file);
	return 0;
}

2.3.2 文件锁

fcntl()函数
P46

记录锁又可以分为______和______,其中前者又称为______,后者又称为______。

  • 读取锁,写入锁
  • 共享锁
  • 排斥锁

fcntl()函数中lock结构体取值含义
P47

2.3.3 多路复用

I/O处理的模型有以下五种:

  • 阻塞I/O模型
  • 非阻塞I/O模型
  • I/O多路转接模型
  • 信号驱动I/O模型
  • 异步I/O模型

详见P51

select()函数语法要点

  • 详见P52

poll()函数语法要点

  • 详见P53

multiplex_poll.c
新建in1和in2两个文件,全部过程都要sudo,否则权限不够

/* multiplex_poll.c */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define MAX_BUFFER_SIZE		1024	/* 缓冲区大小 */
#define IN_FILES			3		/* 多路复用输入文件数目 */
#define TIME_DELAY			60000	/* 超时时间秒数:60秒 */
#define MAX(a, b)		((a > b) ? (a) : (b))

int main(void)
{
	struct pollfd fds[IN_FILES];
	char buf[MAX_BUFFER_SIZE];
	int i, res, real_read, maxfd;
	
	/*首先按一定的权限打开两个源文件*/
	fds[0].fd = 0;
	if((fds[1].fd = open ("in1", O_RDONLY|O_NONBLOCK)) < 0)
	{
		printf("Open in1 error\n");
		return 1;
	}  		    
 	if((fds[2].fd = open ("in2", O_RDONLY|O_NONBLOCK)) < 0)
 	{
 		printf("Open in2 error\n");
		return 1;
	}
	/*取出两个文件描述符中的较大者*/
  	for (i = 0; i < IN_FILES; i++)
  	{
  		fds[i].events = POLLIN;
  	}
  	
  	/* 循环测试是否存在正在监听的文件描述符 */
  	while(fds[0].events || fds[1].events || fds[2].events)
  	{
		if (poll(fds, IN_FILES, 0) < 0) 
		{
			printf("Poll error or Time out\n");
			return 1;
		}		
		for (i = 0; i< IN_FILES; i++)
		{
			if (fds[i].revents) /* 判断在哪个文件上发生了事件*/
			{
				memset(buf, 0, MAX_BUFFER_SIZE);
				real_read = read(fds[i].fd, buf, MAX_BUFFER_SIZE);
				if (real_read < 0)
				{
					if (errno != EAGAIN)
					{
						return 1; /* 系统错误,结束运行*/
					}
				}
				else if (!real_read)
				{
					close(fds[i].fd);
					fds[i].events = 0; /* 取消对该文件的监听 */
				}
				else
				{
					if (i == 0) /* 如果在标准输入上有数据输入时 */
					{
						if ((buf[0] == 'q') || (buf[0] == 'Q'))
						{
							return 1; /*输入"q"或"Q"则会退出*/
						}
					}
					else
					{ /* 将读取的数据先是到终端上 */
						buf[real_read] = '\0';
						printf("%s", buf);
					}
				} /* end of if real_read*/
			} /* end of if revents */
		} /* end of for */
  	} /*end of while */
  	exit(0);
}

2.4 嵌入式Linux串口应用编程

串口属性的配置流程:

    1. 保留原先串口配置
    1. 激活选项
    1. 设置波特率
    1. 设置字符大小
    1. 设置奇偶校验位
    1. 设置停止位
    1. 设置最少字符和等待时间
    1. 清除串口缓冲
    1. 激活配置

2.5 标准 I/O 编程

标准I/O提供了3种类型的缓冲存储

  • 全缓冲
  • 行缓冲
  • 不带缓冲

详见P70

fopen()函数语法要点

  • P71

字符输出函数语法要点

  • P74

实验:文件读写及上锁
终端1:

./producer 1 20

终端2:

./customer 5

producer.c

/* producer.c */
#include 
#include 
#include 
#include 
#include 
#include "mylock.h"

#define MAXLEN			10		/* 缓冲区大小最大值*/

#define ALPHABET		1		/* 表示使用英文字符 */
#define ALPHABET_START		'a'	/* 头一个字符,可以用 'A'*/
#define COUNT_OF_ALPHABET	26	/* 字母字符的个数 */

#define DIGIT			2		/* 表示使用数字字符 */
#define DIGIT_START		'0'		/* 头一个字符 */
#define COUNT_OF_DIGIT		10	/* 数字字符的个数 */

#define SIGN_TYPE	ALPHABET	/* 本实例选用英文字符 */
const char *fifo_file = "./myfifo";	/* 仿真FIFO文件名 */
char buff[MAXLEN];			/* 缓冲区 */

/* 功能:生产一个字符并写入到仿真FIFO文件中 */
int product(void)
{
	int fd;
	unsigned int sign_type, sign_start, sign_count, size;
	static unsigned int counter = 0;
	
	/* 打开仿真FIFO文件 */
	if ((fd = open(fifo_file, O_CREAT|O_RDWR|O_APPEND, 0644)) < 0)
	{
		printf("Open fifo file error\n");
		exit(1);
	}
	
	sign_type =  SIGN_TYPE;
	switch(sign_type)
	{
		case ALPHABET:/* 英文字符 */
		{
			sign_start = ALPHABET_START;
			sign_count = COUNT_OF_ALPHABET;
		}
		break;

		case DIGIT:/* 数字字符 */
		{
			sign_start = DIGIT_START;	
			sign_count = COUNT_OF_DIGIT;
		}
		break;

		default:
		{
			return -1;
		}
	}/*end of switch*/

	sprintf(buff, "%c", (sign_start + counter));
	counter = (counter + 1) % sign_count;
	
	lock_set(fd, F_WRLCK); /* 上写锁*/
	if ((size = write(fd, buff, strlen(buff))) < 0)
	{
		printf("Producer: write error\n");
		return -1;
	}
	lock_set(fd, F_UNLCK); /* 解锁 */

	close(fd);
	return 0;
}

int main(int argc ,char *argv[])
{
	int time_step = 1; /* 生产周期 */
	int time_life = 10; /* 需要生产的资源总数 */

	if (argc > 1)
	{/* 第一个参数表示生产周期 */
		sscanf(argv[1], "%d", &time_step);
	}
	
	if (argc > 2)
	{/* 第二个参数表示需要生产的资源数 */
		sscanf(argv[2], "%d", &time_life);
	}
	while (time_life--)
	{
		if (product() < 0)
		{
			break;
		}
		sleep(time_step);
	}

	exit(EXIT_SUCCESS);
}

customer.c

/* customer.c */
#include 
#include 
#include 
#include 

#define MAX_FILE_SIZE		100 * 1024 * 1024 /* 100M*/

const char *fifo_file = "./myfifo";		/* 仿真FIFO文件名 */
const char *tmp_file = "./tmp";				/* 临时文件名 */

/* 资源消费函数 */
int customing(const char *myfifo, int need)
{
	int fd;
	char buff;
	int counter = 0;
	
	if ((fd = open(myfifo, O_RDONLY)) < 0)
	{
		printf("Function customing error\n");
		return -1;
	}

	printf("Enjoy:");
	lseek(fd, SEEK_SET, 0);
	while (counter < need)
	{	
		while ((read(fd, &buff, 1) == 1) && (counter < need))
		{
			fputc(buff, stdout); /* 消费就是在屏幕上简单的显示 */
			counter++;
		}
	}		
	fputs("\n", stdout);
	close(fd);
	return 0;	
}

/* 功能:从sour_file文件的offset偏移处开始
将count个字节数据拷贝到dest_file文件 */
int myfilecopy(const char *sour_file, 
const char *dest_file, int offset, int count, int copy_mode)
{
	int in_file, out_file;
	int counter = 0;
	char buff_unit;

	if ((in_file = open(sour_file, O_RDONLY|O_NONBLOCK)) < 0)
	{
		printf("Function myfilecopy error in source file\n");
		return -1;
	}
	
	if ((out_file = open(dest_file, 
O_CREAT|O_RDWR|O_TRUNC|O_NONBLOCK, 0644)) < 0)
	{
		printf("Function myfilecopy error in destination file:");
		return -1;
	}

	lseek(in_file, offset, SEEK_SET);
	while ((read(in_file, &buff_unit, 1) == 1) && (counter < count))
	{
		write(out_file, &buff_unit, 1);
		counter++;
	}
	
	close(in_file);
	close(out_file);
	return 0;
}

/* 功能:实现FIFO消费者 */
int custom(int need)
{
	int fd;

	/* 对资源进行消费,need表示该消费的资源数目 */
	customing(fifo_file, need);
	
	if ((fd = open(fifo_file, O_RDWR)) < 0)
	{
		printf("Function myfilecopy error in source_file:");
		return -1;
	}

	/* 为了模拟FIFO结构,对整个文件内容进行平行移动 */
	lock_set(fd, F_WRLCK);
 	myfilecopy(fifo_file, tmp_file, need, MAX_FILE_SIZE, 0);
	myfilecopy(tmp_file, fifo_file, 0, MAX_FILE_SIZE, 0);
	lock_set(fd, F_UNLCK);
	unlink(tmp_file);	
	close(fd);
	return 0;
}

int main(int argc ,char *argv[])
{
	int customer_capacity = 10;
	
	if (argc > 1) /* 第一个参数指定需要消费的资源数目,默认值为10 */
	{
		sscanf(argv[1], "%d", &customer_capacity);
	}
	if (customer_capacity > 0)
	{
		custom(customer_capacity);
	}
	exit(EXIT_SUCCESS);
}

第3章 嵌入式 Linux 多任务编程

3.1.2 任务

任务,进程和线程之间的关系

  • P92

进程的基本概念:

  • P92

进程具有______ , ______ , ______ , ______和______等主要特性

  • 并发性
  • 动态性
  • 交互性
  • 独立性
  • 异步性

Linux系统包括以下3种类型的进程

  • 交互式进程
  • 批处理进程
  • 实时进程

详解见P93

Linux中进程有一下几种状态

  • 运行状态
  • 可中断的阻塞状态
  • 不可中断的阻塞状态
  • 可终止的阻塞状态
  • 暂停状态
  • 跟踪状态
  • 僵尸状态
  • 僵尸撤销状态

详解见P94

获取当前进程号和父进程号的函数分别为:

  • getpid()
  • getppid()

进程的终止中,父进程得到信息后,开始调用______函数族

  • wait()

3.1.3 线程

线程是系统中函数执行和资源分配的基本单位,它是进程内独立的一条运行路线,是处理器调度的最小单元,也可以称为轻量级进程

进程和线程之间的关系图

  • P98

线程总共分为以下三种

    1. 用户级线程
    1. 轻量级线程
    1. 内核线程

fork函数语法要点及简单示例程序
P99-P100
fork.c

#include   
#include    
int main ()   
{   
    pid_t fpid; //fpid表示fork函数返回的值  
    int count=0;  
    fpid=fork();   
    if (fpid < 0)   
        printf("error in fork!");   
    else if (fpid == 0) {  
        printf("i am the child process, my process id is %d/n",getpid());   
        printf("我是爹的儿子/n");  
        count++;  
    }  
    else {  
        printf("i am the parent process, my process id is %d/n",getpid());   
        printf("我是孩子他爹/n");  
        count++;  
    }  
    printf("统计结果是: %d/n",count);  
   return 0;  
}  
//    i am the child process, my process id is 5574
//    我是爹的儿子
//    统计结果是: 1
//    i am the parent process, my process id is 5573
//    我是孩子他爹
//    统计结果是: 1

在进程中调用exec函数族有两种情况:

  • P101

exec函数族使用示例
execlp.c

/* execlp.c */
#include 
#include 
#include 

int main()
{
	if(fork() == 0)
	{
		/* 调用execlp()函数,这里相当于调用了"ps -ef"命令 */
		if((ret = execlp("ps", "ps", "-ef", NULL)) < 0)
		{
			printf("Execlp error\n");
		}
	}
}

exit()和_exit()函数

  • P105

exit()函数使用示例
exit.c

/* exit.c */
#include 
#include 

int main()
{
	printf("Using exit...\n");
	printf("This is the content in buffer");
	exit(0);
}

_exit()函数使用示例
_exit.c

/* _exit.c */
#include 
#include 

int main()
{
	printf("Using _exit...\n");
	printf("This is the content in buffer");
	_exit(0);
}

wait()和waitpid()函数格式说明

  • P107

waitpid()函数示例
waitpid.c

/* waitpid.c */
#include 
#include 
#include 
#include 
#include 

int main()
{
	pid_t pc, pr;

	pc = fork();
	if( pc < 0 )
	{
			printf("Error fork\n");
			exit(1);
	}
	else if( pc == 0 )	/* 子进程 */
	{
		/* 子进程暂停5s */
		sleep(5);
		/* 子进程正常退出 */
		exit(0);
	}
	else	/* 父进程 */
	{
		/* 循环测试子进程是否退出 */
		do
		{
			/* 调用waitpid,且父进程不阻塞 */
			pr = waitpid(pc, NULL, WNOHANG);

			/* 若子进程还未退出,则父进程暂停1s */
			if( pr == 0 )
			{
				printf("The child process has not exited\n");
				sleep(1);
			}
		}while( pr == 0 );

		/* 若发现子进程退出,打印出相应情况 */
		if( pr == pc )
		{
			printf("Get child exit code: %d\n",pr);
		}
		else
		{
			printf("Some error occured.\n");
		}
	}
}

3.3.2 Linux 守护进程

守护进程概述

  • P110

编写守护进程的五步

  • P110

程序阅读题:daemon.c
daemon.c

/* daemon.c创建守护进程实例 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main()
{
	pid_t pid;
	int i, fd;
	char* buf = "This is a Daemon\n";

	pid = fork();	/* 第一步 */
	if(pid < 0)
	{
		printf("Error fork\n");
		exit(1);
	}
	else if(pid > 0)
	{
		exit(0);	/* 父进程退出 */
	}

	setsid();	/* 第二步 */
	chdir("/");	/* 第三步 */
	umask(0);	/* 第四步 */
	for(i = 0; i < getdtablesize(); i++)	/* 第五步 */
	{
		close(i);
	}

	/* 这时创建完守护进程,以下开始正式进入守护进程工作 */
	while(1)
	{
		if((fd = open("/tmp/daemon.log", O_CREAT | O_WRONLY | O_APPEND, 0600)) < 0)
		{
			printf("Open file error\n");
			exit(1);
		}
		write(fd, buf, strlen(buf) + 1);
		close(fd);
		sleep(10);
	}
	return 0;
}

3.2.3 Linux僵尸进程

僵尸进程的产生条件

  • P118

实验:编写多进程程序
multi_proc_wrong.c

/* multi_proc_wrong.c */
#include 
#include 
#include 
#include 
#include 

int main(void)
{
	pid_t child1, child2, child;
	/*创建两个子进程*/
	child1 = fork();
	child2 = fork();
	/*子进程1的出错处理*/
	if (child1 == -1)
	{
		printf("Child1 fork error\n");
		exit(1);
	}
	else if (child1 == 0) /*在子进程1中调用execlp()函数*/
	{
         	printf("In child1: execute 'ls -l'\n");
		if (execlp("ls", "ls", "-l", NULL) < 0)
		{
			printf("Child1 execlp error\n");
		}
  	}
  	
  	if (child2 == -1) /*子进程2的出错处理*/
  	{
  		printf("Child2 fork error\n");
  		exit(1);
  	}
  	else if( child2 == 0 ) /*在子进程2中使其暂停5s*/
  	{
  		printf("In child2: sleep for 5 seconds and then exit\n");
  		sleep(5);
  		exit(0);
  	}
  	else /*在父进程中等待两个子进程的退出*/
  	{
  		printf("In father process:\n");
  		child = waitpid(child1, NULL, 0); /* 阻塞式等待 */
  		if (child == child1)
  		{
  			printf("Get child1 exit code\n");
  		}
  		else
  		{
  			printf("Error occured!\n");
  		}
  		
  		do
  		{
  			child = waitpid(child2, NULL, WNOHANG);/* 非阻塞式等待 */
  			if (child == 0)
  			{
  				printf("The child2 process has not exited!\n");
  				sleep(1);
  			}
  		} while (child == 0);
  		
  		if (child == child2)
		{
			printf("Get child2 exit code\n");
		}
		else
		{
			printf("Error occured!\n");
		}
	}
	return 0;
}

multi_proc.c

/* multi_proc.c */
#include 
#include 
#include 
#include 
#include 

int main(void)
{
	pid_t child1, child2, child;
	
	/*创建两个子进程*/
	child1 = fork();		
	/*子进程1的出错处理*/
	if (child1 == -1)
	{
		printf("Child1 fork error\n");
		exit(1);
	}
	else if (child1 == 0) /*在子进程1中调用execlp()函数*/
	{
		printf("In child1: execute 'ls -l'\n");
		if (execlp("ls", "ls", "-l", NULL) < 0)
		{
			printf("Child1 execlp error\n");
		}
  	}
  	else /*在父进程中再创建进程2,然后等待两个子进程的退出*/
  	{
  		child2 = fork();
  		if (child2 == -1) /*子进程2的出错处理*/
  		{
  			printf("Child2 fork error\n");
  			exit(1);
  		}
  		else if(child2 == 0) /*在子进程2中使其暂停5s*/
  		{
  			printf("In child2: sleep for 5 seconds and then exit\n");
			sleep(5);
			exit(0);
		}

		printf("In father process:\n");
		child = waitpid(child1, NULL, 0); /* 阻塞式等待 */
  		if (child == child1)
  		{
  			printf("Get child1 exit code\n");
  		}
  		else
  		{
  			printf("Error occured!\n");
  		}
  		
  		do
  		{
  			child = waitpid(child2, NULL, WNOHANG);/* 非阻塞式等待 */
  			if (child == 0)
  			{
  				printf("The child2 process has not exited!\n");
  				sleep(1);
  			}
  		} while (child == 0);
  		
  		if (child == child2)
		{
			printf("Get child2 exit code\n");
		}
		else
		{
			printf("Error occured!\n");
		}
	}
	return 0;
}

第4章 嵌入式 Linux 进程间通信

无名管道

  • P133

有名管道

  • P133

管道读写示例

pipe.c

/* pipe.c */
#include 
#include 
#include 
#include 
#include 
#define MAX_DATA_LEN	256
#define DELAY_TIME	1

int main()
{
	pid_t pid;
	int pipe_fd[2];
	char buf[MAX_DATA_LEN];
	const char data[] = "Pipe Test Program";
	int real_read, real_write;
	
	memset((void*)buf, 0, sizeof(buf));
	if (pipe(pipe_fd) < 0) /* 创建管道 */
	{
		printf("pipe create error\n");
		exit(1);
	}
	if ((pid = fork()) == 0) /* 创建一子进程 */
	{
		/* 子进程关闭写描述符,并通过使子进程暂停1秒等待父进程已关闭相应的读描述符 */
		close(pipe_fd[1]);
		sleep(DELAY_TIME * 3);
		/* 子进程读取管道内容 */
		if ((real_read = read(pipe_fd[0], buf, MAX_DATA_LEN)) > 0)
		{
			printf("%d bytes read from the pipe is '%s'\n", real_read, buf);
		}
		close(pipe_fd[0]); /* 关闭子进程读描述符 */
		exit(0);
	}
	else if (pid > 0)
	{
		/* 父进程关闭读描述符,并通过使父进程暂停1秒等待子进程已关闭相应的写描述符 */
		close(pipe_fd[0]);
		sleep(DELAY_TIME);
		if((real_write = write(pipe_fd[1], data, strlen(data))) !=  -1)
		{
			printf("Parent wrote %d bytes : '%s'\n", real_write, data);
		}
		close(pipe_fd[1]); /*关闭父进程写描述符*/
		waitpid(pid, NULL, 0); /*收集子进程退出信息*/
		exit(0);
	}
}

4.3 信号通信

信号概述

  • P142

相应信号的3种方式

  • 忽略信号
  • 捕捉信号
  • 执行默认操作

信号发送:kill()和raise()

  • P144

信号发送与捕捉
kill_raise.c

/* kill_raise.c */
#include 
#include 
#include 
#include 
#include 

int main()
{
	pid_t pid;
	int ret;
	
	/* 创建一子进程 */
	if((pid = fork()) < 0)
	{
		printf("Fork error\n");
		exit(1);
	}

	if(pid == 0)
	{
		/* 在子进程中使用raise()函数发出SIGSTOP信号,使子进程暂停 */
		printf("Child(pid : %d) is waiting for any signal\n",getpid());
		raise(SIGSTOP);
		exit(0);
	}
	else
	{
		/* 在父进程中收集子进程发出的信号,并调用kill()函数进行相应的操作 */
		if((waitpid(pid, NULL, WNOHANG)) == 0)
		{
			if((ret == kill(pid, SIGKILL)) == 0)
			{
				printf("Parent kill %d\n",pid);
			}
		}

		waitpid(pid, NULL, 0);
		exit(0);
	}
}

alarm_pause.c
alarm_pause.c

/* alarm_pause.c */
#include 
#include 
#include 

int main()
{
	/* 调用alarm定时器函数 */
	int ret = alarm(5);
	pause();
	printf("I have been waken up.\n");	/* 此语句不会被执行 */
	return 0;
}

4.4.1 信号概述

信号量概念

  • P153

PV 原子操作具体定义

  • P153

使用信号量分为以下4个步骤

  • P154

共享内存定义

  • P158

消息队列:一些消息的列表

有名管道通信实验
pipe_select.c

/* pipe_select.c*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define FIFO1				"in1"
#define FIFO2				"in2"
#define MAX_BUFFER_SIZE		1024			/* 缓冲区大小*/
#define IN_FILES			3				/* 多路复用输入文件数目*/
#define TIME_DELAY			60				/* 超时值秒数 */
#define MAX(a, b)			((a > b)?(a):(b))

int main(void)
{
	int fds[IN_FILES];
	char buf[MAX_BUFFER_SIZE];
	int i, res, real_read, maxfd;
	struct timeval tv;
	fd_set inset,tmp_inset;
	
	fds[0] = 0;		
	
	/* 创建两个有名管道 */
	if (access(FIFO1, F_OK) == -1) 
	{
		if ((mkfifo(FIFO1, 0666) < 0) && (errno != EEXIST))
		{
			printf("Cannot create fifo file\n");
			exit(1);
		}
	}
	if (access(FIFO2, F_OK) == -1) 
	{
		if ((mkfifo(FIFO2, 0666) < 0) && (errno != EEXIST))
		{
			printf("Cannot create fifo file\n");
			exit(1);
		}
	}
		
	/* 以只读非阻塞方式打开两个管道文件 */
	if((fds[1] = open (FIFO1, O_RDONLY|O_NONBLOCK)) < 0)
	{
		printf("Open in1 error\n");
		return 1;
	}  		    
 	if((fds[2] = open (FIFO2, O_RDONLY|O_NONBLOCK)) < 0)
 	{
 		printf("Open in2 error\n");
		return 1;
	}

	/*取出两个文件描述符中的较大者*/
  	maxfd = MAX(MAX(fds[0], fds[1]), fds[2]);
  	/*初始化读集合inset,并在读文件描述符集合中加入相应的描述集*/
  	FD_ZERO(&inset); 
  	for (i = 0; i < IN_FILES; i++)
  	{
  		FD_SET(fds[i], &inset);
  	}
  	FD_SET(0, &inset);

  	tv.tv_sec = TIME_DELAY;
  	tv.tv_usec = 0;
    /*循环测试该文件描述符是否准备就绪并调用select()函数对相关文件描述符做相应操作*/
  	while(FD_ISSET(fds[0],&inset) 
|| FD_ISSET(fds[1],&inset) || FD_ISSET(fds[2], &inset))
  	{ 
		/* 文件描述符集合的备份, 免得每次进行初始化 */
  		tmp_inset = inset; 
  		res = select(maxfd + 1, &tmp_inset, NULL, NULL, &tv);
  		switch(res)
  		{
  			case -1:
  			{
  				printf("Select error\n");
  				return 1;
  			}
  			break;  			
  			case 0: /* Timeout */
  			{
  				printf("Time out\n");
  				return 1;
  			}  			
  			break;  			
  			default:
  			{
  				for (i = 0; i < IN_FILES; i++)
  				{
  					if (FD_ISSET(fds[i], &tmp_inset))
		  			{
		  				memset(buf, 0, MAX_BUFFER_SIZE);
		  				real_read = read(fds[i], buf, MAX_BUFFER_SIZE);
		  				if (real_read < 0)
		  				{
		  					if (errno != EAGAIN)
		  					{
		  						return 1;
		  					}
		  				}
		  				else if (!real_read)
		  				{
		  					close(fds[i]);
		  					FD_CLR(fds[i], &inset);
		  				}
		  				else
		  				{
		  					if (i == 0)
		  					{  /* 主程序终端控制 */
		  						if ((buf[0] == 'q') || (buf[0] == 'Q'))
		  						{
		  							return 1;
		  						}
							}
		  					else
		  					{  /* 显示管道输入字符串 */
		  						buf[real_read] = '\0';
		  						printf("%s", buf);
		  					}
		  				}
		  			} /* end of if */  					
  				} /* end of for */
  			}
  			break;  		  			
  		} /* end of switch */ 		
  	} /* end of while */
	return 0;
}

共享内存实验
shm_com.h

/* shm_com.h */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define SHM_BUFF_SZ 2048
struct shm_buff
{
	int pid;
	char buffer[SHM_BUFF_SZ];
};

producer.c

/* producer.c */
#include "shm_com.h"
#include "sem_com.c"
#include 
int ignore_signal(void)
{ /* 忽略一些信号,免得非法退出程序 */
	signal(SIGINT, SIG_IGN);
	signal(SIGSTOP, SIG_IGN);
	signal(SIGQUIT, SIG_IGN);
	return 0;
}

int main()
{
	void *shared_memory = NULL;
	struct shm_buff *shm_buff_inst;
	char buffer[BUFSIZ];
	int shmid, semid;
	/* 定义信号量,用于实现访问共享内存的进程之间的互斥*/
  	ignore_signal(); /* 防止程序非正常退出 */
	semid = semget(ftok(".", 'a'),  1, 0666|IPC_CREAT); /* 创建一个信号量*/
	init_sem(semid);/* 初始值为1 */

	/* 创建共享内存 */
	shmid = shmget(ftok(".", 'b'), sizeof(struct shm_buff), 0666|IPC_CREAT);
	if (shmid == -1)
	{
		perror("shmget failed");
		del_sem(semid);
		exit(1);
	}
	
	/* 将共享内存地址映射到当前进程地址空间 */
	shared_memory = shmat(shmid, (void*)0, 0);
	if (shared_memory == (void*)-1)
	{
		perror("shmat");
		del_sem(semid);
		exit(1);
	}
	printf("Memory attached at %X\n", (int)shared_memory);
	/* 获得共享内存的映射地址 */
	shm_buff_inst = (struct shared_use_st *)shared_memory;
	do
	{
		sem_p(semid);	
		printf("Enter some text to the shared memory(enter 'quit' to exit):");
		/* 向共享内存写入数据 */
		if (fgets(shm_buff_inst->buffer, SHM_BUFF_SZ, stdin) == NULL)
		{
			perror("fgets");
			sem_v(semid);
			break;
		}
		shm_buff_inst->pid = getpid();		
		sem_v(semid);
	} while(strncmp(shm_buff_inst->buffer, "quit", 4) != 0);

	/* 删除信号量 */
	del_sem(semid);
	/* 删除共享内存到当前进程地址空间中的映射 */
	if (shmdt(shared_memory) == 1)
	{
		perror("shmdt");
		exit(1);
	}
	exit(0);
}

customer.c

/* customer.c */
#include "shm_com.h"
#include "sem_com.c"

int main()
{
	void *shared_memory = NULL;
	struct shm_buff *shm_buff_inst;
	int shmid, semid;
	/* 获得信号量 */
	semid = semget(ftok(".", 'a'),  1, 0666);
	if (semid == -1)
	{	
		perror("Producer is'nt exist");
		exit(1);
	}
	/* 获得共享内存 */
	shmid = shmget(ftok(".", 'b'), sizeof(struct shm_buff), 0666|IPC_CREAT);
	if (shmid == -1)
	{
		perror("shmget");
		exit(1);
	}
	/* 将共享内存地址映射到当前进程地址空间 */
	shared_memory = shmat(shmid, (void*)0, 0); 
	if (shared_memory == (void*)-1)
	{
		perror("shmat");
		exit(1);
	}
	printf("Memory attached at %X\n", (int)shared_memory);
	/* 获得共享内存的映射地址 */
	shm_buff_inst = (struct shm_buff *)shared_memory;
	do
	{
		sem_p(semid);
		printf("Shared memory was written by process %d :%s"
, shm_buff_inst->pid, shm_buff_inst->buffer);
		if (strncmp(shm_buff_inst->buffer, "quit", 4) == 0) 
		{
			break;
		}
		shm_buff_inst->pid = 0;
		memset(shm_buff_inst->buffer, 0, SHM_BUFF_SZ);
		sem_v(semid);
	} while(1);

	/* 删除共享内存到当前进程地址空间中的映射 */
	if (shmdt(shared_memory) == -1)
	{
		perror("shmdt");
		exit(1);
	}
	/* 删除共享内存 */
	if (shmctl(shmid, IPC_RMID, NULL) == -1)
	{
		perror("shmctl(IPC_RMID)");
		exit(1);
	}
	exit(0);
}

第5章 嵌入式 Linux 多线程编程

pthread_create()

  • P179

互斥锁可以分为______ ,______ ,______。

  • 快速互斥锁
  • 递归互斥锁
  • 检错互斥锁

信号量互斥操作和信号量同步操作流程图

  • P184

线程属性

绑定属性

  • P187

分离属性

  • P187

第6章 嵌入式 Linux 网络编程

北平无战事,六章无大题
OSI模型和TCP/IP参考模型对应关系

  • P198

TCP/IP 分层模型的4个特点以及各自特性

  • P199-P200

socket定义

  • P203

套接字类型

  • 流式套接字
  • 数据报套接字
  • 原始套接字

sockaddr和sockaddr_in

  • P204

inet_pton()函数特点

  • P206

gethostbyaddr()和getaddrinfo()函数

  • P207

P209程序要读懂

P211两个流程图

你可能感兴趣的:(期末复习,linux,运维,服务器)