函数指针、函数指针数组详解及典型应用_韦东山 函数指针数组-程序员宅基地

技术标签: c语言  嵌入式linux学习笔记  C语言学习  指针  嵌入式  

20200305 杨千嬅唱的《处处吻》真是太好听了,下个他他吻她他吻她吻他吻她… 已沉醉

一、何为函数指针

我们知道指针变量指向内存单元的地址,比如存放普通变量int a;的地址的就是一重指针,存放一重指针变量的地址的就是二重指针,指针变量存地址,以此来实现传址调用,
函数指针,顾名思义,就是指向函数的指针,那么何为指向函数呢?按照上面的逻辑,我们得有一个指针变量,这个指针变量里存放着该函数块在内存中的首地址。
要想理解这个,我们要从指针的层次上理解函数——函数的函数名实际上就是该函数的代码在内存中的首地址的别名,说白了还是个地址,这个有点类似于数组名和数组首元素地址的关系,随便找个反汇编代码就可印证上面所说的,下面的是汇编代码和反汇编调用main函数的例子
1.关于别名:586、587行
2.关于调用:我们可以看看汇编中是如何调用函数的,可以发现,PC指向了文字池中的内容30000848,这不正是mian函数的首地址吗,传址调用就好了
在这里插入图片描述

二、函数指针变量的类型及定义

类型表征着特征,而能够描述一个函数的特征的无非就是入口参数(形参)和返回值了

形式1:返回类型(*函数指针变量名)(参数表)

char*pFun)(int); //定义了一个名为pFun的函数指针变量,要求指向的函数的要有一个int类型的形参并要求该函数返回值为char类型
char glFun(int a)
{
    
	return a;
}
void main()
{
    
	pFun =glFun;
	
	/*函数指针的普通使用,以下两种方式个都可*/
	pFun (2);//与其指向的函数用法无异  
	(*pFun)(2);//此处*pf两端括号必不可少  
}

第1行:pFun是 char (*)(int) 类型的指针
第2行:定义了一个函数glFun().该函数正好是一个以int为参数返回char的函数。即char (int) 类型
第8行:指针变量pFun指向了glFun函数的首地址

形式2:使用typedef更直接

typedef char(*PTRFUN)(int)
PTRFUN pFun;
char glFun(int a)
{
    
	return a;
}
void main()
{
    
	pFun = glFun;
	(*pFun)(2);
}

typedef的功能是定义新的类型。第一句就是定义了一种PTRFUN的类型,并定义这种类型为指向某种函数的指针,这种函数以一个int为参数并返回char类型。

三、举例说明用途

简单的计算函数回调

#include <stdio.h>
#define SIZE 4
/*typedef的功能是定义新的类型。
下面这句就是定义了一种PFUNC的类型,并定义这种类型为指向某种函数的指针,这种函数以两个int为参数并返回int类型。*/
typedef int (*PFUNC)(int, int);
PFUNC fucp_arr[SIZE] = {
    NULL};
int add(int a, int b)
{
    
	return a + b;
}
int sub(int a, int b)
{
    
	return a - b;
}
int mul(int a, int b)
{
    
	return a * b;
}
int div(int a, int b)
{
    
	return b ? a / b : -1;
}

/*返回函数类型,实现函数回调*/
PFUNC calc_func(char op)
{
    
	switch (op)
	{
    
	case '+':
		return add;
	case '-':
		return sub;
	case '*':
		return mul;
	case '/':
		return div;
	default:
		return NULL;
	}
	return NULL;
}
	int main(void)
{
    

	/*无论是什么类型的指针,在32位系统下都占4字节*/
	printf("sizeof(PFUNC) = %d\n", sizeof(PFUNC));
	/*实现函数回调*/
	printf("%d + %d = %d\n", 13, 14, (calc_func('+'))(13, 14));
	printf("%d - %d = %d\n", 13, 14, (calc_func('-'))(13, 14));
	printf("%d * %d = %d\n", 13, 14, (calc_func('*'))(13, 14));
	printf("%d / %d = %d\n", 13, 14, (calc_func('/'))(13, 14));
	
	return 0;
}


编译运行后得到

root@youngfar-PC:/mnt/hgfs/Linux教程/mytest# gcc -o exe test.c -m32
root@youngfar-PC:/mnt/hgfs/Linux教程/mytest# ./exe
sizeof(PFUNC) = 4
13 + 14 = 27
13 - 14 = -1
13 * 14 = 182
13 / 14 = 0

四、利用函数指针数组进行函数的注册和调用

#include <stdio.h>
#define SIZE 4
/*typedef的功能是定义新的类型。
下面这句就是定义了一种PFUNC的类型,并定义这种类型为指向某种函数的指针,这种函数以两个int为参数并返回int类型。*/
typedef int (*PFUNC)(int, int);
PFUNC fucp_arr[SIZE] = {
    NULL};
int add(int a, int b)
{
    
	return a + b;
}
int sub(int a, int b)
{
    
	return a - b;
}
int mul(int a, int b)
{
    
	return a * b;
}
int div(int a, int b)
{
    
	return b ? a / b : -1;
}

/*返回函数类型,实现函数回调*/
PFUNC calc_func(char op)
{
    
	switch (op)
	{
    
	case '+':
		return add;
	case '-':
		return sub;
	case '*':
		return mul;
	case '/':
		return div;
	default:
		return NULL;
	}
	return NULL;
}

/* 
 不使用typedef,直接让函数返回一个函数指针,写起来比较麻烦,不直观,所以不推荐

 定义了一个函数,s_calc_func是函数名,
 s_calc_func这个函数需要char类型的形参,
 且最终返回一个函数指针,
 且要求这个函数指针指向的函数有两个int类型的形参和一个int类型的返回值
 */
int (*s_calc_func(char op))(int, int) /* 注意:这个函数的用途与上一个名为calc_func的函数的作业和调用方式完全相同*/
{
    
	return calc_func(op);
}

/*我们要从指针的层次上理解函数-函数的函数名实际上就是一个指针,函数名指向该函数的代码在内存中的首地址。*/
void Fp_Register(int position, PFUNC fp)
{
    
	fucp_arr[position] = fp;
}

int main(void)
{
    
/*无论是什么类型的指针,在32位系统下都占4字节*/
	printf("sizeof(PFUNC) = %d\n", sizeof(PFUNC));
	// /*实现函数回调*/
	// printf("%d + %d = %d\n", 13, 14, (calc_func('+'))(13, 14));
	// printf("%d - %d = %d\n", 13, 14, (calc_func('-'))(13, 14));
	// printf("%d * %d = %d\n", 13, 14, (calc_func('*'))(13, 14));
	// printf("%d / %d = %d\n", 13, 14, (calc_func('/'))(13, 14));

	/*函数注册*/
	Fp_Register(0, add);
	Fp_Register(1, sub);
	Fp_Register(2, mul);
	Fp_Register(3, div);

	/*函数调用*/
	printf("%d + %d = %d\n", 13, 14, fucp_arr[0](13, 14));
	printf("%d - %d = %d\n", 13, 14, fucp_arr[1](13, 14));
	printf("%d * %d = %d\n", 13, 14, fucp_arr[2](13, 14));
	printf("%d / %d = %d\n", 13, 14, fucp_arr[3](13, 14));

	return 0;
}

运行结果和上边的一样

函数指针数组应用实例

函数指针数组一般用于有相同操作流程但细节却不能使用一个函数统一描述的的函数的调用,比如在2440处理中断时的一些操作,下面贴出代码,举例说明,先来看2440中断的处理流程
在这里插入图片描述
The S3C2440A has two interrupt pending registers: source pending register (SRCPND) and interrupt pending register (INTPND). These pending registers indicate whether an interrupt request is pending or not. When the interrupt sources request interrupt the service, the corresponding bits of SRCPND register are set to 1, and at the same time, only one bit of the INTPND register is set to 1 automatically after arbitration procedure. If interrupts are masked, then the corresponding bits of the SRCPND register are set to 1. This does not cause the bit of INTPND register changed. When a pending bit of INTPND register is set, the interrupt service routine will start whenever the I-flag or F-flag is cleared to 0. The SRCPND and INTPND registers can be read and written, so the service routine must clear the pending condition by writing a 1 to the corresponding bit in the SRCPND register first and then clear the pending condition in the INTPND registers by using the same method.
S3C2440A有两个中断暂挂寄存器:源暂挂寄存器(SRCPND)和中断暂挂寄存器(INTPND)。这些挂起的寄存器指示中断请求是否挂起。当中断源请求中断服务时,SRCPND寄存器的相应位被设置为1,同时,经过仲裁程序,INTPND寄存器中只有1位被设置为1。如果中断被屏蔽,那么SRCPND寄存器的相应位被设置为1。这不会导致INTPND寄存器的位发生变化。当设置一个暂挂的INTPND寄存器位时,中断服务例程将在I-flag或F-flag被清除为0时启动。SRCPND和INTPND寄存器可以读写,因此服务例程必须先通过将1写入SRCPND寄存器中相应的位来清除挂起条件,然后使用相同的方法清除INTPND寄存器中的挂起条件。
在这里插入图片描述
在这里插入图片描述
下面是2440代码的按键中断处理函数

#include "s3c2440_soc.h"

/* SRCPND 用来显示哪个中断产生了, 需要清除对应位
 * bit0-eint0
 * bit2-eint2
 * bit5-eint8_23
 */

/* INTMSK 用来屏蔽中断, 1-masked
 * bit0-eint0
 * bit2-eint2
 * bit5-eint8_23
 */

/* INTPND 用来显示当前优先级最高的、正在发生的中断, 需要清除对应位
 * bit0-eint0
 * bit2-eint2
 * bit5-eint8_23
 */

/* INTOFFSET : 用来显示INTPND中哪一位被设置为1
 */

/* 初始化中断控制器 Initial State 为1, 0 = Service available*/
void interrupt_init(void)
{
    
	INTMSK &= ~((1 << 0) | (1 << 2) | (1 << 5)); /*按键中断源配置*/
	INTMSK &= ~(1 << 10);						 /* timer0 中断源配置*/
}

/* 初始化按键, 设为中断源 */
void key_eint_init(void)
{
    
	/* 配置GPIO为中断引脚 */
	GPFCON &= ~((3 << 0) | (3 << 4));
	GPFCON |= ((2 << 0) | (2 << 4)); /* S2,S3被配置为中断引脚 */

	GPGCON &= ~((3 << 6) | (3 << 22));
	GPGCON |= ((2 << 6) | (2 << 22)); /* S4,S5被配置为中断引脚 */

	/* 设置中断触发方式: 双边沿触发 */
	EXTINT0 |= (7 << 0) | (7 << 8); /* S2,S3 */
	EXTINT1 |= (7 << 12);			/* S4 */
	EXTINT2 |= (7 << 12);			/* S5 */

	/* 设置EINTMASK使能eint11,19 */
	EINTMASK &= ~((1 << 11) | (1 << 19));
}

/* 读EINTPEND分辨率哪个EINT产生(eint4~23)
 * 清除中断时, 写EINTPEND的相应位
 */

void key_eint_irq(int irq)
{
    
	unsigned int val = EINTPEND;
	unsigned int val1 = GPFDAT;
	unsigned int val2 = GPGDAT;

	if (irq == 0) /* eint0 : s2 控制 D12 */
	{
    
		if (val1 & (1 << 0)) /* s2 --> gpf6 */
		{
    
			/* 松开 */
			GPFDAT |= (1 << 6);
		}
		else
		{
    
			/* 按下 */
			GPFDAT &= ~(1 << 6);
		}
	}
	else if (irq == 2) /* eint2 : s3 控制 D11 */
	{
    
		if (val1 & (1 << 2)) /* s3 --> gpf5 */
		{
    
			/* 松开 */
			GPFDAT |= (1 << 5);
		}
		else
		{
    
			/* 按下 */
			GPFDAT &= ~(1 << 5);
		}
	}
	else if (irq == 5) /* eint8_23, eint11--s4 控制 D10, eint19---s5 控制所有LED */
	{
    
		if (val & (1 << 11)) /* eint11 */
		{
    
			if (val2 & (1 << 3)) /* s4 --> gpf4 */
			{
    
				/* 松开 */
				GPFDAT |= (1 << 4);
			}
			else
			{
    
				/* 按下 */
				GPFDAT &= ~(1 << 4);
			}
		}
		else if (val & (1 << 19)) /* eint19 */
		{
    
			if (val2 & (1 << 11))
			{
    
				/* 松开 */
				/* 熄灭所有LED */
				GPFDAT |= ((1 << 4) | (1 << 5) | (1 << 6));
			}
			else
			{
    
				/* 按下: 点亮所有LED */
				GPFDAT &= ~((1 << 4) | (1 << 5) | (1 << 6));
			}
		}
	}

	EINTPEND = val; //写1清除中断标志
}

void handle_irq_c(void)
{
    
	/* 分辨中断源 */
	int bit = INTOFFSET;

	/* 调用对应的处理函数 */
	if (bit == 0 || bit == 2 || bit == 5) /* eint0,2,eint8_23 */
	{
    
		key_eint_irq(bit); /* 处理中断, 清中断源EINTPEND */
	}
	else if (bit == 10)
	{
    
		timer_irq();
	}

	/* 清中断 : 从源头开始清 */
	SRCPND = (1 << bit);
	INTPND = (1 << bit);
}

每次编写中断相关函数需要

汇编中:
1.中断发生前:

01.设置中断向量表
02.调用c中的mian函数

2.中断发生时:

跳转到中断向量表,去执行相应的处理(硬件自动)
01.设置 sp_irq
02.保存现场 :
在irq异常处理函数中有可能会修改r0-r12, 所以先保存
lr-4是异常处理完后的返回地址, 也要保存
05. 汇编中调用c中断处理函数处理中断
06. 恢复现场

C语言中 :
3.中断发生前

01.main函数由汇编调用,初始化各个中断控制器,配置中断源

4.中断发生时:

由汇编调用中断处理函数,该函数应包含:
01.中断产生时分辨中断源
02.调用对应的处理函数
03.清中断标志

函数指针数组主要用来解决上述 4 中断处理函数的流程调用,未使用函数指针数组时,每配置中断,都需要改变handle_irq_c来完成 4 中的01、02、03,改动interrupt_init来配置对应的MASK位,而使用之后我们就不需要改动了,由上述 2 中的05调用 后可自动配置,也是一种优化,下面是使用函数指针数组改进后的代码:

#include "s3c2440_soc.h"

typedef void(*irq_func)(int) ;
irq_func irq_array[32];


/* SRCPND 用来显示哪个中断产生了, 需要清除对应位
 * bit0-eint0
 * bit2-eint2
 * bit5-eint8_23
 */

/* INTMSK 用来屏蔽中断, 1-masked
 * bit0-eint0
 * bit2-eint2
 * bit5-eint8_23
 */

/* INTPND 用来显示当前优先级最高的、正在发生的中断, 需要清除对应位
 * bit0-eint0
 * bit2-eint2
 * bit5-eint8_23
 */

/* INTOFFSET : 用来显示INTPND中哪一位被设置为1
 */

/* 初始化中断控制器 */
// void interrupt_init(void)
// {
    
// 	INTMSK &= ~((1<<0) | (1<<2) | (1<<5));
// 	INTMSK &= ~(1<<10);  /* enable timer0 int */
// }

/* 读EINTPEND分辨率哪个EINT产生(eint4~23)
 * 清除中断时, 写EINTPEND的相应位
 */


void key_eint_irq(int irq)
{
    
	unsigned int val = EINTPEND;
	unsigned int val1 = GPFDAT;
	unsigned int val2 = GPGDAT;
	
	if (irq == 0) /* eint0 : s2 控制 D12 */
	{
    
		if (val1 & (1<<0)) /* s2 --> gpf6 */
		{
    
			/* 松开 */
			GPFDAT |= (1<<6);
		}
		else
		{
    
			/* 按下 */
			GPFDAT &= ~(1<<6);
		}
		
	}
	else if (irq == 2) /* eint2 : s3 控制 D11 */
	{
    
		if (val1 & (1<<2)) /* s3 --> gpf5 */
		{
    
			/* 松开 */
			GPFDAT |= (1<<5);
		}
		else
		{
    
			/* 按下 */
			GPFDAT &= ~(1<<5);
		}
		
	}
	else if (irq == 5) /* eint8_23, eint11--s4 控制 D10, eint19---s5 控制所有LED */
	{
    
		if (val & (1<<11)) /* eint11 */
		{
    
			if (val2 & (1<<3)) /* s4 --> gpf4 */
			{
    
				/* 松开 */
				GPFDAT |= (1<<4);
			}
			else
			{
    
				/* 按下 */
				GPFDAT &= ~(1<<4);
			}
		}
		else if (val & (1<<19)) /* eint19 */
		{
    
			if (val2 & (1<<11))
			{
    
				/* 松开 */
				/* 熄灭所有LED */
				GPFDAT |= ((1<<4) | (1<<5) | (1<<6));
			}
			else
			{
    
				/* 按下: 点亮所有LED */
				GPFDAT &= ~((1<<4) | (1<<5) | (1<<6));
			}
		}
	}

	EINTPEND = val;
}


void handle_irq_c(void)
{
    
	/* 分辨中断源 */
	int bit = INTOFFSET;

	/* 调用对应的处理函数 */
	irq_array[bit](bit);
	
	/* 清中断 : 从源头开始清 */
	SRCPND = (1<<bit);
	INTPND = (1<<bit);	
}

void register_irq(int irq, irq_func fp)
{
    
	irq_array[irq] = fp;

	INTMSK &= ~(1<<irq);
}


/* 初始化按键, 设为中断源 */
void key_eint_init(void)
{
    
	/* 配置GPIO为中断引脚 */
	GPFCON &= ~((3<<0) | (3<<4));
	GPFCON |= ((2<<0) | (2<<4));   /* S2,S3被配置为中断引脚 */

	GPGCON &= ~((3<<6) | (3<<22));
	GPGCON |= ((2<<6) | (2<<22));   /* S4,S5被配置为中断引脚 */
	

	/* 设置中断触发方式: 双边沿触发 */
	EXTINT0 |= (7<<0) | (7<<8);     /* S2,S3 */
	EXTINT1 |= (7<<12);             /* S4 */
	EXTINT2 |= (7<<12);             /* S5 */

	/* 设置EINTMASK使能eint11,19 */
	EINTMASK &= ~((1<<11) | (1<<19));

	register_irq(0, key_eint_irq);
	register_irq(2, key_eint_irq);
	register_irq(5, key_eint_irq);
}


只需在初始化时注册一下相应的处理函数
register_irq(0, key_eint_irq);
register_irq(2, key_eint_irq);
register_irq(5, key_eint_irq);
待到中断到来时即可自动完成 分辨中断源 、调用对应的处理函数 、清中断这一系列操作,时代码更加便于维护

注:本文参考了
typedef函数指针的用法(C++)

C/C++ 函数指针使用总结

和韦东山老师的讲解,转载请注明出处,本人初学Linux,如有错误,欢迎评论区批评指出,共同进步

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_28816873/article/details/104684373

智能推荐

配置Ipv4地址,脚本怎么写_脚本地址怎么填-程序员宅基地

文章浏览阅读3.8k次。在公司项目开发的时候需要将项目部署在不同的服务器上,部署时你需要进行ip的切换,接下来我来介绍俩种配置方法。第一种首先点击桌面右下角的电脑图标,用鼠标右击打开Internet设置。进入到如下界面,点击以太网,点击右边的更改适配器配置。然后进入到如下界面,双击如下图标。然后进入到如下界面,双击属性。进入到如下界面,双击如下图标。进入到如下界面,黄色部分为ip和网关填上去就好,..._脚本地址怎么填

JVM调优专题-内存溢出及解决方案_jvm调优 堆内存溢出-程序员宅基地

文章浏览阅读1.6k次。吃撑过吗?吃多了还想吃咋办?当然JVM也有吃撑了的时候,甚至撑到程序宕机卡死,后果很严重。本节我们一起探讨如何判断JVM内存溢出、以及其解决方案。_jvm调优 堆内存溢出

「生存即赚」链接现实与游戏,打造3T平台生态

3T游戏的推出,旨在聚合资源,开拓新的市场领域,为整个行业创造更多的增长点和价值空间。抵抗者算力救助:为了缓解玩家在游戏中可能遭受的损失,当玩家所在的房间被攻破时,虽然他们投入的USDT或3TC会损失,但作为补偿,玩家将获得相应比例的3TC算力救助,这种机制既体现了游戏的人文关怀,又为玩家提供了继续参与游戏的动力。3T游戏平台解决的不仅仅是玩家游戏体验的问题,它还将区块链技术与DEFI和跨链相结合,链接全球的各个环节,让用户可以在不同链上进行游戏交互,享受更加多样化和丰富的游戏体验,打造3T游戏生态。

可视化配置 Nginx 代理:功能完备,使用简单 | 开源日报 No.234

想要轻松管理 Nginx 代理主机和 SSL 证书吗?试试一下 nginx-proxy-manager 吧!拥有简单强大的界面和各种功能优势,让您无需深入了解 Nginx 或 Let's Encrypt,就能轻松实现反向代理和 SSL 证书管理。赶快体验吧!

C语言高级-存储类、作用域、生命周期、链接属性_内存链接属性-程序员宅基地

文章浏览阅读2.6k次。第一点概念解析存储类一个变量的存储类属性就是描述这个变量存储在何种内存段中;作用域对以下函数进行解读如图可知虽然在for循环内部定义了a,但是在函数外部定义的a++还是显示错误,显示没有定义;这就是作用域的问题!生命周期生命周期就是描述这个变量什么时候诞生(运行时分配内存空间给这个变量)以及什么时候死亡(就是收回给这个变量分配的内存空间)的时间间隔!链接属性编译是将源代码的.C文件编译成.O文件(单个的二进制机器码格式),.O文件中就有很多的符号和代码段、数据段、_内存链接属性

关于pt、px、pc的区别_xcqpcpx-程序员宅基地

文章浏览阅读6.1k次。pt 点(Point)。绝对长度单位。 1in = 2.54cm = 25.4 mm = 72pt = 6pc px 像素(Pixel)。相对长度单位。 像素是相对于显示器屏幕分辨率而言的。譬如,WONDOWS的用户所使用的分辨率一般是96像素/英寸。而MAC的用户所使用的分辨率一般是72像素/英寸。 pc 派卡(Pica)。绝对长度单位。相当于我国新四号铅字的尺寸。 1in = 2.54cm =_xcqpcpx

随便推点

Java+Mysql +SpringBoot个人网盘系统92922-计算机毕业设计(可赠源码)_springboot 网盘-程序员宅基地

文章浏览阅读281次,点赞5次,收藏7次。该平台采用的数据库是Mysql,SpringBoot框架,使用Java技术开发。在设计过程中,充分保证了系统代码的良好可读性、实用性、易扩展性、通用性、便于后期维护、操作方便以及页面简洁等特点。个人网盘系统是以实际运用为开发背景,运用软件工程原理和开发方法,采用Java技术构建的一个线上系统。整个开发过程首先对软件系统进行需求分析,得出系统的主要功能。接着对系统进行总体设计和详细设计。_springboot 网盘

基于微信小程序的体育课评分系统+ssm+vue.js附带文章和源代码设计说明文档ppt-程序员宅基地

文章浏览阅读719次,点赞25次,收藏16次。博主介绍:CSDN特邀作者、985计算机专业毕业、某互联网大厂高级全栈开发程序员、码云/掘金/华为云/阿里云/InfoQ/StackOverflow/github等平台优质作者、专注于Java、小程序、前端、python等技术领域和毕业项目实战,以及程序定制化开发、全栈讲解、就业辅导、面试辅导、简历修改。精彩专栏 推荐订阅2023-2024年最值得选的微信小程序毕业设计选题大全:100个热门选题推荐2023-2024年最值得选的Java毕业设计选题大全:500个热门选题推荐。

Python 三种读文件方法read(), readline(), readlines()及去掉换行符\n_python 文件读取 \n-程序员宅基地

文章浏览阅读5.3w次,点赞36次,收藏134次。Python 三种读文件方法read(), readline(), readlines()及去掉换行符\n首先, 让我们看下数据demo.txt, 就两行数据.35durantteamGSW1. read()with open("demo.txt", "r") as f: data = f.read() print(data) print(ty..._python 文件读取 \n

Python sklearn MLP 报错 ValueError: Unknown label type: (array..._valueerror: unknown label type: (array(-程序员宅基地

文章浏览阅读2.3k次,点赞4次,收藏4次。原因:这是因为用的是MLPClassifier分类器,但是y_data也就是报错中的label为小数,分类器的话,输出只能使整数。解决:换成调用MLPRegressor回归器每列数据分别乘10n10^n10n使小数变成整数_valueerror: unknown label type: (array(

VxWorks中信号量实现任务间通信与同步机制分析_信号量集可以多任务间的数据通讯-程序员宅基地

文章浏览阅读1.9k次。引 言多任务内核、任务调度机制、任务间通信和中断处理机制,这些都是VxWorks运行环境的核心。多任务处理和任务间通信是实时操作系统的基石。一个多任务环境允许将一个实时应用构造成一套独立任务的集合,每一个都有自己独立的执行路线和自己的系统资源,完成不同的功能。任务间通信的机制则允许任务间的同步和通信,以调整系统的行为。VxWorks中,任务间通信的机制包括从快速信号量到消息队列、管道、网络传输套接_信号量集可以多任务间的数据通讯

invalidate()和postInvalidate()的区别_postinvalidate和invalidate的区别-程序员宅基地

文章浏览阅读847次。invalidate()与postInvalidate()都用于刷新View,主要区别是invalidate()在主线程中调用,若在子线程中使用需要配合handler;而postInvalidate()可在子线程中直接调用。postInvalidate它是向主线程发送个Message,然后handleMessage时,调用了invalidate()函数。(系统帮我们 写好了 Handle..._postinvalidate和invalidate的区别