linux开发板sleep函数,Linux模拟实现sleep函数

先来说说工作原理,linux中的sleep函数能够让程序休眠一定的秒数,到时间后自动恢复运行。

实现思路

设定睡眠的秒数

睡眠(挂起)

恢复运行

实现机制

设定睡眠的秒数:采用alarm()函数设定需要睡眠的秒数,到时间后闹钟会发送sigalrm信号给当前进程。但sigalrm信号的默认操作是杀死进程,所以我们需要对sigalrm信号进行自定义处理。

睡眠:pause()函数会让当前进程挂起,直到收到信号才会出错返回。

示例程序代码:模拟实现sleep使当前进程每2秒打印”hello yingying\n”

#include

#include

#include

void handler(int signo)//由于程序在睡眠期间什么也不做所以自定义处理函数不执行任何操作

{

}

int mysleep(int time)

{

sigset_t set;

sigemptyset(&set);

struct sigaction act;

struct sigaction oact;

act.sa_handler = handler;//自定义处理函数

act.sa_mask = set;

act.sa_flags = 0;

sigaction(sigalrm,&act,&oact);//捕捉闹钟信号自定义处理动作

alarm(time);//time秒后给进程发送信号

pause();//挂起进程

int _time = alarm(0);//如果程序被提前唤醒取消闹钟

sigaction(sigalrm,&oact,null);//恢复捕捉信号的原始状态

return _time;

}

int main()

{

while(1)

{

printf("hello yingying\n");

mysleep(2);

}

return 0;

}

问题分析

上述代码在看似没有问题可以实现我们需要的结果,但是带 多执行流下仍可以正常运行吗?例如在设定了闹钟后当前进程被切换出去,等再切换回来闹钟已经响过了,那么当前进程就会被永远挂起。所以我们需要优化上面的程序。

.优化方案一:

1.屏蔽sigalrm信号

2.alarm(time)

3.解除屏蔽sigalrm信号

4.pause()

.优化方案二:1.屏蔽sigalrm信号

2.alarm(time)

3.pause()

4.解除屏蔽sigalrm信号

这两种方案大家思考一下可行吗?应该选哪个呢?

方案选择

对于方案一:如果进程在解除屏蔽之后,pause()之前的的间隙被切走仍会造成同样的问题,进程也可能被永远挂起。

对于方案二:程序挂起之后,闹钟信号被屏蔽,一直处于未决状态,程序无法收到信号,进程也就会被一直挂起。所以方案二是不可以选择的。

对于方案一我们可以改进,使解除阻塞与挂起成为一个原子操作这样就可以解决我们的问题了。

解决问题

像方案一这种由时序问题导致程序出现问题的情况成为竞态条件。sigsuspend()函数可以实现pause()函数的挂起功能,同时也能解决竞态条件的问题。sigsuspend()函数的功能就是-“解除信号屏蔽”-“挂起进程等待信号”-“执行信号处理函数”- “出错返回”。所以sigsuspend()函数函数同pause()函数一样只有出错返回值。在对程序时序要求比较严格的程序中一般使用sigsuspend()函数。

优化后的程序代码

#include

#include

#include

void handler(int signo)

{

}

int mysleep(int time)

{

sigset_t set,oset,susmask;

sigemptyset(&set);

sigaddset(&set,sigalrm);

sigprocmask(sig_block,&set,&oset);

struct sigaction act;

struct sigaction oact;

act.sa_handler = handler;

act.sa_mask = set;

act.sa_flags = 0;

sigaction(sigalrm,&act,&oact);

alarm(time);

susmask = oset;

sigdelset(&susmask,sigalrm);

sigsuspend(&susmask);

int _time = alarm(0);

sigaction(sigalrm,&oact,null);

sigprocmask(sig_block,&oset,null);

return _time;

}

int main()

{

while(1)

{

printf("hello yingying\n");

mysleep(2);

}

return 0;

}

这样我们的sleep函数的模拟实现就完成了。

程序结果

9620a1be0f1eec570a9ba6c67875589c.png

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持萬仟网。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是基于K210开发板的DHT11型号的温湿度传感器驱动函数,代码如下: ```c #include "dht11.h" #include <stdio.h> #include <unistd.h> #include <gpiohs.h> #include <gpio.h> #include <encoding.h> #include <sysctl.h> #include <printf.h> // 定义数据引脚 #define DHT11_DATA_PIN 4 // DHT11 初始化函数 void dht11_init(void) { // 配置数据引脚为输出模式 gpiohs_set_drive_mode(DHT11_DATA_PIN, GPIO_DM_OUTPUT); // 发送起始信号,拉低至少18ms gpiohs_set_pin(DHT11_DATA_PIN, GPIO_PV_LOW); sleep(20); // 拉高至少20us gpiohs_set_pin(DHT11_DATA_PIN, GPIO_PV_HIGH); usleep(20); } // DHT11 读取数据函数 int dht11_read_data(dht11_data_t *data) { // 定义变量 uint8_t i, j; uint8_t byte_index = 0; uint8_t bit_index = 7; uint8_t byte_data[5] = {0}; uint8_t check_sum = 0; // 发送起始信号 dht11_init(); // 切换到输入模式 gpiohs_set_drive_mode(DHT11_DATA_PIN, GPIO_DM_INPUT); // 等待 DHT11 响应,低电平 80us,高电平 80us while (gpiohs_get_pin(DHT11_DATA_PIN)); while (!gpiohs_get_pin(DHT11_DATA_PIN)); while (gpiohs_get_pin(DHT11_DATA_PIN)); // 开始读取数据 for (i = 0; i < 40; i++) { // 等待数据位,低电平 50us,高电平 26-28us 表示 0,高电平 70us 表示 1 while (!gpiohs_get_pin(DHT11_DATA_PIN)); usleep(30); if (gpiohs_get_pin(DHT11_DATA_PIN)) { byte_data[byte_index] |= (1 << bit_index); } if (bit_index == 0) { bit_index = 7; byte_index++; } else { bit_index--; } } // 校验数据 check_sum = byte_data[0] + byte_data[1] + byte_data[2] + byte_data[3]; if (check_sum != byte_data[4]) { return -1; } // 保存数据 data->humidity = byte_data[0]; data->temperature = byte_data[2]; // 返回成功 return 0; } // DHT11 测试函数 void dht11_test(void) { // 定义变量 dht11_data_t data = {0}; // 读取数据 if (dht11_read_data(&data) == 0) { // 输出温湿度 printf("Temperature: %d Celsius, Humidity: %d%%\n", data.temperature, data.humidity); } else { printf("Read data failed!\n"); } } ``` 注意:这里使用了GPIOHS库进行开发,需要在工程中添加该库的支持,同时需要根据实际情况修改数据引脚的编号。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值