信号可靠性剖析

问题

基于信号发送的进程间通信方式可靠吗???

信号分为不可靠信号和可靠信号,使用可靠信号的方式来实现进程间通信是可靠的

信号查看(kill -l)

信号的分类

不可靠信号 (传统信号)

  • 信号值在 [1, 31] 之间的所有信号

可靠信号 (实时信号)

  • 信号值在 [SIGRTMIN,SIGRTMAX],即:[34,64]
  • SIGRTMIN => 34
  • SIGRTMAX => 64

信号小知识

信号 32 与信号 33 (SIGCANCEL & SIGSETXID) 被NPTL 线程库征用

NPTL => Native Posix  Threading Library

  • 即:POSIX 线程标准库,Linux 可以使用这个库进行多线程编程

对于 Linux 内核,信号 32 是最小的可靠信号

SIGRTMIN 在 signal.h 中定义,不同平台的 linux 可能不同 (arm linux)

不可靠信号 vs 可靠信号

不可靠信号

  • 内核不保证信号可以递送到目标进程 (内核对信号状态进行标记)
  • 如果信号处于未决状态,并且相同信号被发送,内核丢弃后续相同信号

可靠信号

  • 内核维护信号队列,未决信号位于队列中,因此信号不会被丢弃
  • 严格意义上,信号队列有上限,因此不可以无限制保存可靠信号

一些注意事项。。。

不可靠信号的默认处理行为可能不同 (忽略,结束)

可靠信号的默认处理行为都是结束进程

信号的可靠性由信号数值决定,与发送方式无关

信号队列的上限可通过命令设置

查询信号队列上限:ulimit -i

设置信号队列上限:ulimit -i 1000

信号可靠性试验设计

目标:验证信号可靠性 (不可靠信号 or 可靠信号)

方案:对目标进程 "疯狂" 发送 N 次信号,验证信号处理函数调用次数

预备函数:

  • int sigaddset(sigset* set, int signum);
  • int sigdelset(sigset_t* set, int signum);
  • int sigfillset(sigset_t* set);
  • int sigfillset(sigset* set);
  • int sigemptyset(sigset* set);
  • int sigprocmask(int how, const sigset* set, sigset* oldset);

进程可靠性实验

main1.c


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

static int g_count = 0;
static int g_obj_sig = 0;

void signal_handler(int sig, siginfo_t* info, void* ucontext)
{
    if( sig == g_obj_sig )
    {
        g_count++;
    }
}

int main(int argc, char* argv[])
{
    struct sigaction act = {0};
    sigset_t set = {0};
    int i = 0;
    
    g_obj_sig = atoi(argv[1]);
    
    printf("current pid(%d) ...\n", getpid());

    act.sa_sigaction = signal_handler;
    act.sa_flags = SA_RESTART | SA_SIGINFO;
    
    
    sigaddset(&act.sa_mask, g_obj_sig);
    sigaction(g_obj_sig, &act, NULL);
    
    
  
    sigfillset(&set);
    sigprocmask(SIG_SETMASK, &set, NULL);
    
    for(i=0; i<15; i++)
    {
        sleep(1);
        printf("i = %d\n", i);
    }
    
    sigemptyset(&set);
    sigprocmask(SIG_SETMASK, &set, NULL);
    
    printf("g_count = %d\n", g_count);
    
    return 0;
}

g_obj_sig 是我们测试用的目标信号,第 35 行,我们为目标信号注册信号处理函数 signal_handler()

第 40 行,我们屏蔽所有的信号;随后 sleep 15s,在这 15s 内,我们要发送目标信号;第 49 行,又恢复所有被屏蔽的信号,如果有被屏蔽的目标信号未决,那么会调用到信号处理函数,将 g_count 变量加一;第 51 行,打印 g_count 的次数

test1.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>


int main(int argc, char* argv[])
{
    int pid = atoi(argv[1]);
    int sig = atoi(argv[2]);
    union sigval sv = {1234567};
    int i = 0;
    
    printf("current pid(%d) ...\n", getpid());
    printf("send sig(%d) to process(%d)...\n", sig, pid);
    
    for(i=0; i<5000; i++)
    {
        sigqueue(pid, sig, sv);
    }
    
    return 0;
}

用于发送 5000 次目标信号给指定的进程

我们首先测试不可靠信号,我们将目标信号值设定为 2,程序运行结果如下图所示:

g_count 的值为 1,目标信号的信号处理只处理了一次,说明不可靠信号在未决的时候发送了多次的话,就只会处理一次

之后我们测试可靠信号,我们将目标信号值设定为 40,程序运行结果如下图所示:

g_count 的值为 5000,目标信号的信号处理每次都去处理了

我们使用 ulimit -i 命令查看信号队列的上限

然后,我们将发送端发送目标信号的次数由 5000 改为 10000,查看程序运行结果,程序运行结果如下图所示:

我们发送目标信号发送了 10000 次,但目标信号处理函数只处理了 7606 次,这是因为,可靠信号是保存在信号队列中的,信号队列的长度是受限的,当前系统信号队列的最大个数是 7606,最多只能同时保存 7606 个可靠信号

在可靠信号需要发送的次数比较多的时候,我们需要及时去处理信号,否则可能会导致信号队列满,漏信号

基于信号的进程间通信实验

A 进程将 TLV 类型的数据通过可靠信号传递给 B 进程

  • TLV => (type, length, value)
  • 由于可靠信号的限制,每次传输4字节数据

B 进程首先接收 4 字节数据 (type 或 type + length)

  • 根据接收到 length 信息,多次接收后续的字节数据
  • 每次只能接收 4 字节数据,设计层面需要进行状态处理

状态设计

数据发送进程关键实现

数据接收进程关键实现

进程间通信实验

test2.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>

typedef struct _tlv_t_
{
	short type;
	short length;
	char data[];
} Message;

int main(int argc, char* argv[])
{
    int pid = atoi(argv[1]);
    int sig = atoi(argv[2]);
	char* data = argv[3];
	int len = sizeof(Message) + strlen(data) + 1;
	int size = (len / 4 + !!(len % 4)) * 4;
	
	Message* msg = (Message*)malloc(size);
    
	if(msg)
	{
		int* pi = (int*)msg;
		union sigval sv = {0};
		int i = 0;
		
		printf("current pid(%d) ...\n", getpid());
		printf("send sig(%d) to process(%d)...\n", sig, pid);
		
		msg->type = 0;
		msg->length = size - sizeof(Message);
		strcpy(msg->data, data);
		
		for(i = 0; i < size; i += 4)
		{
			sv.sival_int = *pi++;
			sigqueue(pid, sig, sv);
		}
	}
	
	free(msg);
    
    return 0;
}

使用信号来进程间通信,必须使用可靠信号,否则会丢失数据

由于发送数据的长度不定,所以这里采用了柔性数组,使用 malloc 的方式来分配空间

第 21 行,做了一个 4 字节对齐的操作,这样做可以统一数据的处理方式

main2.c


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

static int g_obj_sig = 0;
static int g_current = -1;
static int g_type = -1;
static int g_length = 0;
static char* g_data = NULL;

static void ipc_data_handler(char* data, int length)
{
	printf("ipc data: %s\n", data);
}

static void signal_handler(int sig, siginfo_t* info, void* ucontext)
{
    if( sig == g_obj_sig )
    {
        if(g_current == -1)
		{
			g_type = info->si_value.sival_int & 0xFF;
			g_length = (info->si_value.sival_int >> 16) & 0xFF;
			g_data = (char*)malloc(sizeof(char) * g_length);
			
			if(!g_data)
			{
				exit(-1);
			}
			else
			{
				g_current = 0;
			}
		}
		else
		{
			int i = 0;
			
			while((i < 4) && (g_current < g_length))
			{
				g_data[g_current++] = (info->si_value.sival_int >> (i * 8)) & 0xFF;
				i++;
			}
		}
		
		if(g_current == g_length)
		{
			ipc_data_handler(g_data, g_length);
			g_current = -1;
			g_length = 0;
			free(g_data);
			g_data = NULL;
		}
    }
}

int main(int argc, char* argv[])
{
    struct sigaction act = {0};
    sigset_t set = {0};
    int i = 0;
    
    g_obj_sig = atoi(argv[1]);
    
    printf("current pid(%d) ...\n", getpid());

    act.sa_sigaction = signal_handler;
    act.sa_flags = SA_RESTART | SA_SIGINFO;
    
    sigaddset(&act.sa_mask, g_obj_sig);
    sigaction(g_obj_sig, &act, NULL);
    
	while(1)
	{
		sleep(1);
	}
	
    return 0;
}

首先解析出 type 和 length,然后根据 length 来读取完整的数据

程序运行结果如下图所示:

我们使用发送可靠信号的方式,接收方成功的接收到了发送方的数据

  • 20
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 信号相干性分析是一种研究不同信号间相互作用关系的技术,其主要应用于信号处理、通信和自动控制等领域。在Matlab中,信号相干性分析可以通过多种工具箱和函数来实现,比如Signal Processing Toolbox、Communications Toolbox、DSP System Toolbox等。 信号相干性分析的主要内容包括功率谱、相关函数、互谱密度、交叉谱密度等,这些指标可以反映出信号之间的相互影响程度和相关性。Matlab中的spectrogram函数和pwelch函数可以用于计算信号的功率谱和互谱密度,xcorr和xcov函数可以用于计算信号的相关函数和交叉谱密度。此外,Matlab还提供了多种可视化工具,比如plot函数、stem函数、surf函数等,可以方便地展示信号分析结果。 在实际应用中,信号相干性分析可以帮助解决多种问题,比如降噪、信号调制和解调、信道估计等。例如,在通信系统中,信号相干性分析可以用于检测和纠正信道失真,提高信号传输的可靠性和效率。因此,熟练掌握信号相干性分析技术,对于提高信号处理和通信系统设计的能力有着重要意义。 ### 回答2: 信号相干性分析是指对信号进行相干度量的过程,它是理解和分析信号特性的重要方法之一。在实际应用中,我们通常使用MATLAB进行信号相干性分析。 MATLAB是一个强大的数学软件工具,具有丰富的信号处理和分析功能,比如功率谱密度分析、信号滤波以及相关性分析等。在信号相干性分析中,MATLAB可以用于计算信号的相干度、相关性和互相关函数等。 在MATLAB中,我们可以通过使用FFT函数计算信号各个频率的幅度和相位信息,进而得到信号的功率谱密度。同时,MATLAB中还提供了许多工具函数,比如cxy、mscohere等,方便用户计算信号之间的相干度和相位关系。 需要注意的是,在信号相干性分析过程中,我们需要考虑信号采样率、信号长度、窗函数等因素的影响,以保证分析结果的精度和可靠性。 总之,MATLAB是一款非常适合信号相干性分析的工具,其丰富的信号处理和分析功能可以帮助用户深入了解信号的特性和行为。 ### 回答3: 信号相干性分析是一种用于研究信号的时域和频域特性的方法。MATLAB是一种可以方便地进行信号处理的工具,是对信号相干性分析进行研究和实验的理想选择。 在MATLAB中,可以使用信号处理工具箱中的各种函数进行信号相干性分析。例如,可以使用xcov函数计算两个信号的互相关函数并进一步计算信号之间的互相干系数。另外,使用welch函数进行谱密度估计可以帮助我们了解信号的频率分布和功率谱密度等信息。还可以使用pwelch函数进行功率谱密度估计,帮助我们检测信号中的周期和频率。 除此之外,MATLAB还提供了一些绘图工具,如plot、stem和freqz等,用于显示和理解信号的时域和频域特性。 总之,使用MATLAB进行信号相干性分析可以为我们提供重要的信号特性信息,使得我们对信号原理和应用方向有更深刻的认识和理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值