d40注意如果一个线程非常频繁访问一个变量,而其他线程又去改变这个变量的值会导致前面的线程因为读错误卡死;最简单的办法就是volatile,加线程不要空转浪费资源,应该加阻塞或者休眠;

https://baike.baidu.com/item/volatile/10606957?fr=ge_ala

加volatile可以解决一个线程非常频繁访问一个变量,而其他线程又去改变这个变量的值会导致前面的线程因为读错误卡死

57d46f05f8274aab98ef6d78e74fc91e.png

5557af3325aa4f569e819abca21f38d5.png

11cb31b06d454ba496603470ced604cf.png

注意如果一个线程非常频繁访问一个变量,而其他线程又去改变这个变量的值会导致前面的线程因为读错误卡死

代码如下:

问题的现象是:当在if(uo->recording == true) { 前面加个打印,线程就能正常运行,一开始以为是内存踩踏问题,但是按如下方法排查发现不是

如何初步判断是不是其他地方内存踩踏造成的指针变量变化-CSDN博客

最后加打印并去掉awi_audio2_uac_out_start对uo->recording变量的操作就能正常运行

原因:可以看出uo->recording != true的时候,这个线程一直在访问uo->recording变量,这时如果其他线程来调用awi_audio2_uac_out_start来改变uo->recording变量的,那么任务调度切换回原线程的时候,就会有风险以为访问出错而有卡死

static void* awi_audio2_uac_out_proc(void *arg)
{
	awi_audio2_uac_out_t *uo;
	awi_alsa_record2_t *ar = NULL;
	awi_alsa_record2_params_t *ar_params;
	snd_pcm_uframes_t frames;
	awi_audio2_uac_out_msg_t *energy_msg;
	uint8_t buffer[AWI_AUDIO2_UAC_OUT_RECORD_BUFFER_SIZE];

	uo = (awi_audio2_uac_out_t*)arg;

	ar_params = &uac_out_params;
	ar = awi_alsa_record2_new(ar_params);
	if(NULL == ar) {
		aw_print("failed to new alsa record");
		goto fail;
	}
	awi_alsa_record2_set_tag(ar, "uac out");
	frames = uac_out_params.period_time * uac_out_params.sample_rate / (1000 * 1000);	

	while(uo->runing) {
		int readed = frames;
		if(uo->recording == true) {
			readed = awi_alsa_record2_read(ar, buffer, frames);			
			if(readed == frames){
				uo->is_play = true;
				energy_msg = awi_audio2_uac_out_pop_msg(uo);
				if(NULL != energy_msg) {
					memcpy(energy_msg->buffer, buffer, AWI_AUDIO2_UAC_OUT_RECORD_BUFFER_SIZE);
					awi_blockqueue_push(&uo->msg_energy_q, &energy_msg->q_n);
				}			
				if (uo->data_func != NULL){
					uo->data_func(uo->data_ths, buffer, AWI_AUDIO2_UAC_OUT_RECORD_BUFFER_SIZE);
				}
			}else{
				uo->is_play = false;
		// #ifdef AUDIO2_DEBUG
				aw_print("unexpect readed %d/%ld", readed, frames);
		// #endif
				if(NULL != ar) {
					awi_alsa_record2_del(ar);
				}
				ar = awi_alsa_record2_new(ar_params);
				if(NULL == ar) {
					aw_print("failed to new alsa record");
				}
				awi_alsa_record2_set_tag(ar, "uac out");
			}
		}	
	}

fail:
	if(NULL != ar) {
		awi_alsa_record2_del(ar);
	}
	return NULL;
}


int awi_audio2_uac_out_start(awi_audio2_uac_out_t *uo)
{
	uo->recording = true;
	return 0;
}

int awi_audio2_uac_out_stop(awi_audio2_uac_out_t *uo)
{
	uo->recording = false;
	return 0;
}

解决如下,可以在代码循环里面加阻塞或者睡眠

或者使用最简单的办法,在竞争的变量前面加volatile

82f35b252fe245d78a362830cbe2d5e9.png

阻塞的可以参考如下,睡眠的话不太好

static void* awi_audio2_uac_out_proc(void *arg)
{
	awi_queue_node_t *qn;
	awi_audio2_uac_out_t *uo;
	awi_alsa_record2_t *ar = NULL;
	awi_alsa_record2_params_t *ar_params;
	snd_pcm_uframes_t frames;
	awi_audio2_uac_out_msg_t *energy_msg;
	uint8_t buffer[AWI_AUDIO2_UAC_OUT_RECORD_BUFFER_SIZE];


	uo = (awi_audio2_uac_out_t*)arg;
	frames = uac_out_params.period_time * uac_out_params.sample_rate / (1000 * 1000);
	while(uo->runing) {
		if(uo->is_connect == true) {
			qn = awi_blockqueue_pop(&uo->msg_q, 0);
		} else {
			qn = awi_blockqueue_pop(&uo->msg_q, -1);
			if(NULL == qn) {
				continue;
			}
		}
		if(NULL != qn) {
			awi_audio2_uac_out_msg_t *msg;

			msg = awi_offset(qn, awi_audio2_uac_out_msg_t, q_n);
			aw_print("msg event = %d", msg->event);
			if(msg->event == AWI_AUDIO2_UAC_OUT_MSG_EVENT_CONNECT) {
				uo->is_connect = true;
				if(ar == NULL) {
					aw_print("uac out connect");
					ar_params = &uac_out_params;
					ar = awi_alsa_record2_new(ar_params);
					if(NULL == ar) {
						aw_print("failed to new alsa record");
						goto fail;
					}
					awi_alsa_record2_set_tag(ar, "uac out");
				}
			} else if(msg->event == AWI_AUDIO2_UAC_OUT_MSG_EVENT_DISCONNECT) {
				uo->is_connect = false;
				if(ar != NULL) {
					aw_print("uac out disconnect");
					awi_alsa_record2_del(ar);
					ar = NULL;
				}
			}
			if (msg != NULL){
				awi_free(msg);
			}
			continue;
		}
		if(uo->is_connect == true && ar != NULL) {
			int readed = awi_alsa_record2_read(ar, buffer, frames);
			energy_msg = awi_audio2_uac_out_pop_msg(uo);
			if(NULL != energy_msg) {
				memcpy(energy_msg->buffer, buffer, AWI_AUDIO2_UAC_OUT_RECORD_BUFFER_SIZE);
				awi_blockqueue_push(&uo->msg_energy_q, &energy_msg->q_n);
			}
			if(readed == frames) {
				uo->is_play = true;
				if(uo->recording == true && uo->data_func != NULL) {
					uo->data_func(uo->data_ths, buffer, AWI_AUDIO2_UAC_OUT_RECORD_BUFFER_SIZE);
				}
			} else {
				uo->is_play = false;
#ifdef AUDIO2_DEBUG
				aw_print("unexpect readed %d/%ld", readed, frames);
#endif
				if(NULL != ar) {
					awi_alsa_record2_del(ar);
				}
				ar = awi_alsa_record2_new(ar_params);
				if(NULL == ar) {
					aw_print("failed to new alsa record");
				}
				awi_alsa_record2_set_tag(ar, "uac out");
			}
		}
	}

fail:
	if(NULL != ar) {
		awi_alsa_record2_del(ar);
	}
	return NULL;
}

还有一点就是线程不要空转,因为空转的时候在运行这个线程的时候就是什么事情不做,那么这个线程的时间片就是浪费了,应该加阻塞或者睡眠,这样子任务调度就不会调这个线程,把cpu给应该用的线程,防止资源的浪费

还需要注意一点:加锁是不能解决这个问题的,不能解决问题是因为下面的加锁有问题,按下文加应该是可以的

使用pthread_cond_wait和pthread_mutex_lock来解决变量竞争的问题-CSDN博客

be672d1372d6471ba2950b6b4bfcb561.png 0d2e453ae77742539e794b457a00b6c8.png

 

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,我会给你一个Verilog的代码实现,顶层模块包括一个时钟模块、一个计数模块和一个七段数码管显示模块,可以实现60进制秒表并使用七段数码管进行显示。 ``` module top( input clk, input rst, output reg [3:0] seg, output reg [6:0] anode ); reg [5:0] sec; reg [5:0] min; reg [5:0] hour; wire [3:0] sec_seg; wire [3:0] min_seg; wire [3:0] hour_seg; // 计数模块 always @(posedge clk or posedge rst) begin if (rst) begin sec <= 6'b0; min <= 6'b0; hour <= 6'b0; end else begin sec <= sec + 6'b1; if (sec == 6'd59) begin sec <= 6'b0; min <= min + 6'b1; if (min == 6'd59) begin min <= 6'b0; hour <= hour + 6'b1; if (hour == 6'd23) begin hour <= 6'b0; end end end end end // 七段数码管显示模块 seven_seg_60 sec_seg_60(.num(sec), .seg(seg_sec)); seven_seg_60 min_seg_60(.num(min), .seg(seg_min)); seven_seg_24 hour_seg_24(.num(hour), .seg(seg_hour)); // 时分秒数码管显示连接 assign seg = {seg_hour, seg_min, seg_sec}; assign anode = 7'b1111110; endmodule module seven_seg_60( input [5:0] num, output reg [3:0] seg ); always @(*) begin case(num) 6'd0: seg = 4'b1110; 6'd1: seg = 4'b0110; 6'd2: seg = 4'b1101; 6'd3: seg = 4'b1111; 6'd4: seg = 4'b0111; 6'd5: seg = 4'b1011; 6'd6: seg = 4'b0011; 6'd7: seg = 4'b1110; 6'd8: seg = 4'b1111; 6'd9: seg = 4'b1111; 6'd10: seg = 4'b1111; 6'd11: seg = 4'b1111; 6'd12: seg = 4'b1111; 6'd13: seg = 4'b1111; 6'd14: seg = 4'b1111; 6'd15: seg = 4'b1111; 6'd16: seg = 4'b1111; 6'd17: seg = 4'b1111; 6'd18: seg = 4'b1111; 6'd19: seg = 4'b1111; 6'd20: seg = 4'b1111; 6'd21: seg = 4'b1111; 6'd22: seg = 4'b1111; 6'd23: seg = 4'b1111; 6'd24: seg = 4'b1111; 6'd25: seg = 4'b1111; 6'd26: seg = 4'b1111; 6'd27: seg = 4'b1111; 6'd28: seg = 4'b1111; 6'd29: seg = 4'b1111; 6'd30: seg = 4'b1111; 6'd31: seg = 4'b1111; 6'd32: seg = 4'b1111; 6'd33: seg = 4'b1111; 6'd34: seg = 4'b1111; 6'd35: seg = 4'b1111; 6'd36: seg = 4'b1111; 6'd37: seg = 4'b1111; 6'd38: seg = 4'b1111; 6'd39: seg = 4'b1111; 6'd40: seg = 4'b1111; 6'd41: seg = 4'b1111; 6'd42: seg = 4'b1111; 6'd43: seg = 4'b1111; 6'd44: seg = 4'b1111; 6'd45: seg = 4'b1111; 6'd46: seg = 4'b1111; 6'd47: seg = 4'b1111; 6'd48: seg = 4'b1111; 6'd49: seg = 4'b1111; 6'd50: seg = 4'b1111; 6'd51: seg = 4'b1111; 6'd52: seg = 4'b1111; 6'd53: seg = 4'b1111; 6'd54: seg = 4'b1111; 6'd55: seg = 4'b1111; 6'd56: seg = 4'b1111; 6'd57: seg = 4'b1111; 6'd58: seg = 4'b1111; 6'd59: seg = 4'b1111; default: seg = 4'b0000; endcase end endmodule module seven_seg_24( input [5:0] num, output reg [3:0] seg ); always @(*) begin case(num) 6'd0: seg = 4'b1110; 6'd1: seg = 4'b0110; 6'd2: seg = 4'b1101; 6'd3: seg = 4'b1111; 6'd4: seg = 4'b0111; 6'd5: seg = 4'b1011; 6'd6: seg = 4'b0011; 6'd7: seg = 4'b1110; 6'd8: seg = 4'b1111; 6'd9: seg = 4'b1111; 6'd10: seg = 4'b0001; 6'd11: seg = 4'b0010; 6'd12: seg = 4'b0100; 6'd13: seg = 4'b1000; 6'd14: seg = 4'b0000; 6'd15: seg = 4'b0000; 6'd16: seg = 4'b0000; 6'd17: seg = 4'b0000; 6'd18: seg = 4'b0000; 6'd19: seg = 4'b0000; 6'd20: seg = 4'b0000; 6'd21: seg = 4'b0000; 6'd22: seg = 4'b0000; 6'd23: seg = 4'b0000; default: seg = 4'b0000; endcase end endmodule ``` 这个代码实现了一个顶层模块,包括一个时钟模块、一个计数模块和一个七段数码管显示模块。时钟模块提供时钟信号,计数模块实现了60进制计数,七段数码管显示模块实现了数字到七段数码管的转换,并将显示结果输出到七段数码管上。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

文武先生hh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值