interrput打断的三种情况

①打断的是正在阻塞中的线程(sleep、wait、join),被打断的线程会抛出InterruptedException异常,打断标记会被清除。

@Slf4j(topic = "c.Test11")
public class Test11 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            log.debug("sleep...");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t1");
        t1.start();
        Thread.sleep(1000);
        log.debug("interrupt");
        t1.interrupt();
        Thread.sleep(1000);
        log.debug("打断标记:{}", t1.isInterrupted());
    }
}
15:47:03.405 [t1] DEBUG c.Test11 - sleep...
15:47:04.408 [main] DEBUG c.Test11 - interrupt
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at cn.itcast.test.Test11.lambda$main$0(Test11.java:14)
	at java.lang.Thread.run(Thread.java:750)
15:47:05.427 [main] DEBUG c.Test11 - 打断标记:false
  • t1在sleep中被主线程打断,抛出InterruptedException异常
  • t1的打断标记被清除了,为false

②打断是正常运行的线程,线程的打断标记不会被清除,为true,线程可以通过判断打断标记,知道有人打断它了,但他停不停,什么时候停,由他自己说了算,他可以在知道自己被打断后,做一些善后工作再结束运行。

public class Test12 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (true) {
                boolean interrupted = Thread.currentThread().isInterrupted();
                if(interrupted) {
                    log.debug("被打断了,俺不玩了");
                    break;
                }
            }
        },"t1");
        t1.start();
        
        Thread.sleep(1000);
        log.debug("interrupt");
        t1.interrupt();
    }
}
16:00:18.645 [main] DEBUG cn.itcast.test.Test12 - interrupt
16:00:18.647 [t1] DEBUG cn.itcast.test.Test12 - 被打断了,俺不玩了
  • 主线程睡眠1s是为了保证t1线程已经开始运行
  • 主线程对t1线程打断后,t1线程可以通过isInterrupted()得到打断标记,知道自己被打断了,做一些善后工作

③打断的是park中的线程,线程会终止park状态,继续运行,但它的打断标记不会被清除,如果不手动清除,那么以后无法再次让该线程park,即该线程park失效。如果想让park再次生效,可以用Thread.interrupted()获取打断标记,它会在获取打断标记后将打断清除。

private static void test() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            log.debug("park...");
            LockSupport.park();
            log.debug("unpark...");
            log.debug("打断状态:{}", Thread.interrupted());
            
            LockSupport.park();
            log.debug("unpark...");
        },"t1");
        t1.start();
        
        Thread.sleep(1000);
        t1.interrupt();
    }
11:05:21.851 [t1] DEBUG c.Test14 - park...
11:05:22.858 [t1] DEBUG c.Test14 - unpark...
11:05:22.858 [t1] DEBUG c.Test14 - 打断状态:true
  • 因为打断标记被清除了,第二次执行park时,仍然有效,t1线程会阻塞住。
#include<reg52.h> #include “Delay.h” #include “LED.h” #include “Segment.h” #include “Init.h” #include “Time.h” #include “Serial.h” #include “EEPROM.h” #define Year 0 #define Month 2 #define Day 4 #define Hour 6 #define Min 8 #define Sec 10 static unsigned char Curtime[][10]={“2025”,“-”,“07”,“-”,“02”," “,“13”,”:“,“12”,”:",“25”,“Wed”}; static unsigned int Channel_Index=0; static unsigned int Count=0; void main() { int* p=&Channel_Index; Clock_Init(); Interrupt_Init(); En_Init(); while(1) { Led(); Segdisp(Channel_Index,Curtime); } } //外部中断KEY1 KEY2 void Key1_Hanlder() interrupt 0 { Channel_Index=0; } void Key2_Hanlder() interrupt 2 { Channel_Index=1; } void Clock_interrput() interrupt 1 { TH0 = 0x3C; TL0 = 0xB0; Count++; if(Count>=20) { Update_time(Curtime); Serial_send(Curtime); Count=0; } } void Serial_interrput() interrupt 4 { static unsigned int i=0,j=0; if(1 == RI) { RI=0; Curtime[j][i++] = SBUF; Delay_ms(5); if(i<12) { i++; } else if(i>11||Curtime[i][j]!=‘\0’) { i=0; j++; if(j>9) { j=0; } } } } #include <reg52.h> #include “EEPROM.h” #include “Delay.h” void IAP_Dsiable(void); static void IAP_Trigger(void); void IAP_Dsiable(void) { ISP_CMD = 0x00; ISP_TRIG = 0x00; ISP_CONTR = 0x00; } static void IAP_Trigger(void) { ISP_TRIG = 0x46; ISP_TRIG = 0xB9; } void IAP_Erase(unsigned int addr) { unsigned int i,j; for(i=0;i<12;i++) { for(j=0;j<10;j++) { ISP_CONTR=0x81; ISP_CMD=0x03; ISP_ADDRH = (unsigned char)(addr >> 8); ISP_ADDRL = (unsigned char) addr; IAP_Trigger(); IAP_Dsiable(); addr++; } } } //读取EEPORM时间 void Read_FixTime(unsigned int addr1,unsigned char Fixtime[][10]) { unsigned int i,j; EA=0; for(i=0;i < 12;i++) { for(j=0;(j <10 )&& (Fixtime[i][j] !=‘\0’);j++) { ISP_CONTR = 0x81; ISP_CMD = 0x01; ISP_ADDRL=addr1; ISP_ADDRH=addr1>>8; IAP_Trigger(); Fixtime[i][j] = ISP_DATA; Delay_ms(10); IAP_Dsiable(); addr1++; } if(j==10) Fixtime[i][j] = ‘\0’; } EA=1; } //存储EEPORM时间 void Save_FixedTime(unsigned int addr2,unsigned char Savetime[][10]) { unsigned int i,j; EA=0; for(i=0;i < 12 ;i++) { for(j=0;j < 10 && Savetime[i][j]!= ‘\0’;j++) { IAP_Erase(addr2); ISP_CONTR = 0x81; ISP_CMD = 0x02; ISP_ADDRL=addr2; ISP_ADDRH=addr2>>8; ISP_DATA = Savetime[i][j]; Delay_ms(10); IAP_Trigger(); IAP_Dsiable(); addr2 ++; } } EA=1; }#ifndef EEPROM_H #define EEPROM_H sfr ISP_DATA=0xe2; sfr ISP_ADDRH=0xe3; sfr ISP_ADDRL=0xe4; sfr ISP_CMD=0xe5; sfr ISP_TRIG=0xe6; sfr ISP_CONTR=0xe7; void Read_FixTime(unsigned int addr1,unsigned char Fixtime[][10]); void Save_FixedTime(unsigned int addr2,unsigned char Savetime[][10]); #endif 优化检查改代码 回答 我们被要求使用中文回答问题,并在回答后提出3-5个相关问题,以“§§相关问题§§”开头。 用户提供了一段C语言代码,看起来是针对8051单片机的(使用了reg52.h),代码涉及时钟、中断、EEPROM操作等。 用户要求“优化检查改代码”,即优化并检查这段代码。 我们将分析代码,指出可能的问题,并提出优化建议。 代码分为两部分:主程序文件(main.c)和EEPROM操作文件(EEPROM.c以及对应的头文件)。 首先,我们分析主程序文件(main.c): 定义了一些宏(Year, Month等)但未使用。 定义了一个二维数组Curtime,用于存储当前时间,初始化为一个固定的时间字符串。 定义了两个全局变量Channel_Index和Count。 main函数中初始化时钟、中断和使能(具体初始化函数未给出,但可以推测)。 主循环中调用Led()、Segdisp()显示时间。 两个外部中断处理函数(Key1和Key2)用于改变Channel_Index。 定时器中断(Timer0)每50ms(假设定时器设置为50ms中断一次)中断一次,Count计数,达到20次(即1秒)后更新时间,发送串口,并清零Count。 串口中断处理函数用于接收数据并更新Curtime数组。 其次,分析EEPROM相关文件(EEPROM.c和EEPROM.h): 提供了IAP(在应用编程)操作函数,包括擦除、读取和写入。 读写操作都是针对一个二维数组(10列,12行)的结构。 可能存在的问题及优化建议: 一、主程序文件: 宏定义未使用:定义了Year、Month等宏,但在代码中并没有使用。建议删除或者使用这些宏来访问时间数组,避免魔术数字。 全局变量:Channel_Index和Count是全局变量,在中断中修改,主循环中读取。注意:主循环读取时,中断可能随时修改,需要考虑原子性(但51单片机是8位,通常读一个字节是原子的,但Count是int,两个字节,可能读的过程中被中断修改导致数据不一致)。建议使用volatile修饰,并考虑在读取时暂时关闭中断(如果对数据一致性要求高)。 串口中断处理函数:接收数据并写入Curtime数组。这里存在几个问题: 静态变量i和j用于记录写入位置,但每次接收一个字符后,i自增两次(一次是赋值,一次是if(i<12)内的i++),这会导致跳过一些位置。 逻辑混乱:接收一个字符后,先赋值给Curtime[j][i++],然后延时5ms(在中断中延时是绝对不推荐的,会阻塞系统),接着判断i<12则又i++,这样实际上每接收一个字符,i增加了2(除非i>=12)。然后当i>11或者当前字符不是结束符(这个判断条件不合理)时,会重置i并增加j。这样会导致写入位置错乱。 另外,二维数组Curtime定义为[][10],即每行最多10个字符(包括结束符),但初始化的字符串有的超过10个(如"2025"是4个,加上结束符5个,但"Wed"是3个,所以初始化的字符串长度不一)。在串口中断中,接收的数据长度可能超过10,导致数组越界。 建议:重新设计串口接收协议,例如使用固定的数据格式(如JSON)或者固定长度,并设置接收缓冲区,在接收到完整一帧数据后再解析并更新Curtime。 定时器中断中,每20次中断(1秒)调用Update_time(未给出)来更新时间,然后串口发送。这里Update_time函数应该会修改Curtime数组,而串口中断也可能同时修改,存在竞争。需要避免同时访问(例如在Update_time和串口发送时暂时关闭串口中断)。 代码风格:Curtime的初始化方式为二维数组,但实际存储的是一维的字符串。可以考虑用一维数组(或者结构体)来存储时间。 中断处理函数中不宜进行复杂操作:定时器中断中调用了Update_time和Serial_send,这两个函数可能比较耗时(特别是串口发送,如果使用阻塞发送且波特率低的话)。建议设置标志位,在主循环中处理。 主循环中调用Led()和Segdisp(),这些显示函数可能是耗时的,需要注意是否会影响实时性。 二、EEPROM文件: IAP_Erase函数:该函数按地址擦除,但擦除操作是按扇区进行的(STC89C52RC的EEPROM实际上是Flash模拟,擦除最小单位是扇区,512字节)。当前函数每次擦除一个字节?这是错误的。擦除操作必须按扇区擦除。所以这里应该修改为:计算起始地址所在的扇区,然后擦除整个扇区。注意:擦除一个扇区会将整个扇区置为0xFF。 Read_FixTime和Save_FixedTime函数:这两个函数都是针对二维数组进行操作,但代码中循环次数固定为12行10列。而传入的数组是12行10列,但每行字符串长度不一定都是10(包括结束符)。在读取和写入时,都是按照固定10个字符(每行)来操作,但实际字符串可能以’\0’结束。这里存在两个问题: 写入时,如果某行字符串长度不足10,则会把后面的0(结束符)也写入,但读取时又会读回这些0,然后赋值给数组,这样数组每行都是10个字符(包括中间可能有很多0)。但原数组可能是以结束符提前结束的。 另外,在读取函数中,内层循环条件为:j <10 且 Fixtime[i][j] !=‘\0’。注意,Fixtime[i][j]在读取前是未初始化的,所以判断条件中的Fixtime[i][j]!='\0’是无效的(因为一开始是随机值)。应该直接读取固定长度,然后在末尾添加结束符。 写入函数中,内层循环条件为:j<10且Savetime[i][j]!=‘\0’。这样写会导致只写入非结束符的内容。但是,如果字符串长度不足10,那么后面就不会写入,而之前擦除是整个扇区擦除(擦除后为0xFF),所以未写入的部分仍然是0xFF。这样读取时,读到的内容就是0xFF,而不是0(结束符)。所以读取后需要手动添加结束符。 读写函数中,每次操作一个字节都重新设置ISP_CONTR、CMD等,效率较低。可以改为先擦除整个扇区,然后一次性写入一个扇区(但需要缓存一个扇区的数据),或者至少连续写入时不要每次都重新设置地址(但51的IAP操作要求每次都要设置)。 在读写操作中,关闭了总中断(EA=0),这是为了防止中断干扰IAP操作(因为IAP操作需要严格的时序,且不能被打断)。但要注意,关闭中断的时间不能太 #include<reg52.h> #include “Delay.h” #include “LED.h” #include “Segment.h” #include “Init.h” #include “Time.h” #include “Serial.h” #include “EEPROM.h” #define Year 0 #define Month 2 #define Day 4 #define Hour 6 #define Min 8 #define Sec 10 static unsigned char Curtime[][10]={“2025”,“-”,“07”,“-”,“02”," “,“13”,”:“,“12”,”:",“25”,“Wed”}; static unsigned int Channel_Index=0; static unsigned int Count=0; void main() { int* p=&Channel_Index; Clock_Init(); Interrupt_Init(); En_Init(); while(1) { Led(); Segdisp(Channel_Index,Curtime); } } //外部中断KEY1 KEY2 void Key1_Hanlder() interrupt 0 { Channel_Index=0; } void Key2_Hanlder() interrupt 2 { Channel_Index=1; } void Clock_interrput() interrupt 1 { TH0 = 0x3C; TL0 = 0xB0; Count++; if(Count>=20) { Update_time(Curtime); Serial_send(Curtime); Count=0; } } void Serial_interrput() interrupt 4 { static unsigned int i=0,j=0; if(1 == RI) { RI=0; Curtime[j][i++] = SBUF; Delay_ms(5); if(i<12) { i++; } else if(i>11||Curtime[i][j]!=‘\0’) { i=0; j++; if(j>9) { j=0; } } } } #include <reg52.h> #include “EEPROM.h” #include “Delay.h” void IAP_Dsiable(void); static void IAP_Trigger(void); void IAP_Dsiable(void) { ISP_CMD = 0x00; ISP_TRIG = 0x00; ISP_CONTR = 0x00; } static void IAP_Trigger(void) { ISP_TRIG = 0x46; ISP_TRIG = 0xB9; } void IAP_Erase(unsigned int addr) { unsigned int i,j; for(i=0;i<12;i++) { for(j=0;j<10;j++) { ISP_CONTR=0x81; ISP_CMD=0x03; ISP_ADDRH = (unsigned char)(addr >> 8); ISP_ADDRL = (unsigned char) addr; IAP_Trigger(); IAP_Dsiable(); addr++; } } } //读取EEPORM时间 void Read_FixTime(unsigned int addr1,unsigned char Fixtime[][10]) { unsigned int i,j; EA=0; for(i=0;i < 12;i++) { for(j=0;(j <10 )&& (Fixtime[i][j] !=‘\0’);j++) { ISP_CONTR = 0x81; ISP_CMD = 0x01; ISP_ADDRL=addr1; ISP_ADDRH=addr1>>8; IAP_Trigger(); Fixtime[i][j] = ISP_DATA; Delay_ms(10); IAP_Dsiable(); addr1++; } if(j==10) Fixtime[i][j] = ‘\0’; } EA=1; } //存储EEPORM时间 void Save_FixedTime(unsigned int addr2,unsigned char Savetime[][10]) { unsigned int i,j; EA=0; for(i=0;i < 12 ;i++) { for(j=0;j < 10 && Savetime[i][j]!= ‘\0’;j++) { IAP_Erase(addr2); ISP_CONTR = 0x81; ISP_CMD = 0x02; ISP_ADDRL=addr2; ISP_ADDRH=addr2>>8; ISP_DATA = Savetime[i][j]; Delay_ms(10); IAP_Trigger(); IAP_Dsiable(); addr2 ++; } } EA=1; }#ifndef EEPROM_H #define EEPROM_H sfr ISP_DATA=0xe2; sfr ISP_ADDRH=0xe3; sfr ISP_ADDRL=0xe4; sfr ISP_CMD=0xe5; sfr ISP_TRIG=0xe6; sfr ISP_CONTR=0xe7; void Read_FixTime(unsigned int addr1,unsigned char Fixtime[][10]); void Save_FixedTime(unsigned int addr2,unsigned char Savetime[][10]); #endif 进行串口优化
07-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值