首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >并发性问题数据损坏异步python-can锁定/队列-嵌套字典

并发性问题数据损坏异步python-can锁定/队列-嵌套字典
EN

Stack Overflow用户
提问于 2022-10-18 19:33:35
回答 2查看 76关注 0票数 0

我即将结束一段漫长的旅程.

如果你有兴趣的话,这是一个很长的故事。https://github.com/hardbyte/python-can/issues/1336

很抱歉,代码片段太长了,但是我不知道我哪里出错了,所以我认为更多就是更多了。

代码如下所示,request_inst()使用来自单片机的dict request_info请求仪表数据,单片机响应,这是由listener获取的。obtain_message()创建了一个存储all_data的未来,这是从listenermsg = await reader.get_message()中产生的。我试图用lock构建这个过程。store_data()是我存储来自单片机的响应数据的地方,这是一个名为all_data的dict。all_datalistener外部打印时显示为零值,如下所示。代码的目的是使all_data在事件循环之外可用,但目前即使有了这个实现,我也无法让all_data在dict中没有零值的情况下出现。

代码语言:javascript
复制
import asyncio
import can
from can.notifier import MessageRecipient
from typing import List

freq = 0.0003

# this is the respond ids and the and the parameter ids of the data
# stored data is suppose to fill up the None with a value
all_data = {268439810: {16512: [None], 16513: [None], 16514: [None], 16515: [None]},
            268444162: {16512: [None], 16513: [None], 16514: [None], 16515: [None]}}

request_info = {286326784: {16512, 16513, 16514, 16515},
                287440896: {16512, 16513, 16514, 16515}}

# all the request ids in that have been configured
cm4_read_ids = [286326784, 287440896]

# all the response ids in that have been configured
mcu_respond_ids = [268439810, 268444162]

# finds arb id and pid and logs the data from the message
# async def store_data(arb_id, msg_data, msg_dlc):
async def store_data(msg: can.Message, lock):
    pid = int.from_bytes(msg.data[0:2], 'little')
    arb_id = msg.arbitration_id
    if arb_id in mcu_respond_ids:
        async with lock:
            if msg.dlc == 5:
                all_data[arb_id][pid][0] = int.from_bytes(msg.data[2:4], 'little', signed=False)
            elif msg.dlc == 7:
                all_data[arb_id][pid][0] = int.from_bytes(msg.data[2:6], 'little', signed=False)
    return all_data

async def request_inst(bus: can.Bus):
    print('Request inst active')
    while True:
        for key in request_info:
            for val in request_info[key]:
                pid = int(val)
                pidbytes = pid.to_bytes(2, 'little')
                msg = can.Message(arbitration_id=key, data=pidbytes)
                bus.send(msg)
                await asyncio.sleep(freq)
                # await store_data(reader)

async def message_obtain(reader: can.AsyncBufferedReader, lock):
    print('Started it the get message process')
    while True:
        await asyncio.sleep(0.01)
        msg = await reader.get_message()
        future = await store_data(msg, lock)
        async with lock:

            print('This is the future')
            print(future)

async def main() -> None:
    with can.Bus(
            interface="socketcan", channel="can0", receive_own_messages=True
    ) as bus:
        # Create Notifier with an explicit loop to use for scheduling of callbacks
        loop = asyncio.get_running_loop()
        reader = can.AsyncBufferedReader()
        lock = asyncio.Lock()

        listeners: List[MessageRecipient] = [reader]

        notifier = can.Notifier(bus, listeners, loop=loop)

        try:
            task1 = asyncio.create_task(request_inst(bus))
            task2 = asyncio.create_task(message_obtain(reader, lock))
            await asyncio.gather(task1, task2)
        except KeyboardInterrupt:

            notifier.stop()
            bus.shutdown()

if __name__ == "__main__":
    asyncio.run(main())

我所看到的问题是,即使在这一页上,我也看到了我认为是并发性的问题。

正如您所看到的,我已经尝试过锁定,但是我仍然看到这些零值出现在all_data中,参见下面,当MCU返回的消息不是零时,pid 16514的balue变为0。

n.b.下面显示不正确数据的输出是来自print(future)的输出

实际值不应该是0,因为它是一个测量值。

代码语言:javascript
复制
b6 = (1016872961).to_bytes(4, 'little')
struct.unpack('<f', b6)
(0.01907348819077015,)

我做了什么蠢事吗?尽管在修改all_data时使用了lock,但感觉好像没有正确地访问侦听器中的数据。

如果我从listeners打印数据,即使all_data返回0值,数据也始终是正确的。

如果有人能帮我的话,我将不胜感激。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-11-11 15:40:39

好吧,好吧,原来我做了一件真的很傻的事。我使用嵌套字典来存储关于不同ids的数据,但是键是相同的。在使用id(id1[some_pid1])id(id2[some_pid1])进行了一些调查之后,我发现这些密钥具有相同的内存地址。

代码语言:javascript
复制
data_dict = {id1: {some_pid1: value, some_pid2: value},
             id2: {some_pid1: value, some_pid2: value}}

这似乎是一种竞赛条件,但实际上,我只是写零(结果是被迫从MCU)到错误的id,因为它与另一个id共享一个密钥。

Whoops

票数 -1
EN

Stack Overflow用户

发布于 2022-10-19 08:14:26

看来问题与软件无关,零是真实存在的。每一天都是学习的日子!

这是高亮显示的发送和顶部显示的响应的PCAN图像。

编辑:确认的MCU响应问题-看起来像在单片机上的固件。我的Rigol不会触发在ID上,所以我不得不1/8的视频,然后屏幕截图,以捕捉它在行动。您可以看到响应都是7字节的空值。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74116542

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档