【问题标题】:Segmentation fault when initializing array初始化数组时出现分段错误
【发布时间】:2018-11-01 21:09:36
【问题描述】:

初始化数组时出现分段错误。

我有一个读取 RFID 标签时的回调函数

IDS = []
def readTag(e):
    epc = str(e.epc, 'utf-8')
    if not epc in IDS:
        now = datetime.datetime.now().strftime('%m/%d/%Y %H:%M:%S')
        IDS.append([epc, now, "name.instrument"])

以及调用它的主函数

def main():
    for x in vals:
        IDS.append([vals[0], vals[1], vals[2]])
    for x in IDS:
        print(x[0])
    r = mercury.Reader("tmr:///dev/ttyUSB0", baudrate=9600)
    r.set_region("NA")

    r.start_reading(readTag, on_time=1500)
    input("press any key to stop reading: ")
    r.stop_reading()

由于IDS.append([epc, now, "name.instrument"]) 行而发生错误。我知道,因为当我用打印调用替换它时,程序会运行得很好。我尝试对数组对象(整数)使用不同的类型,在 append 函数之外创建相同对象的数组等。出于某种原因,只是在“readTag”函数中创建一个数组会导致分段错误,如@987654324 @

有谁知道导致此错误的原因以及如何解决?另外更具体一点,readTag 函数对于前两个(只有两个)调用可以正常工作,但随后它会崩溃,并且具有 start_reading() 函数的 Reader 对象来自水星 api

【问题讨论】:

  • 旁注:您似乎有列表,而不是数组。 python中有数组,但['this']是一个列表。
  • if not epc in IDS: 永远不会满足,因为它目前嵌套在另一个列表中。您想重新检查您的步骤,并确定在这里使用哪种数据结构更好。
  • 同样以后只有列表会附加到IDS,所以列表epc永远不会是in IDS
  • @OluwafemiSule 不错。当我调试分段错误的代码时,我似乎忽略了这一点。谢谢!
  • @AndrasDeak python 新手。我很感激解释!谢谢!

标签: python segmentation-fault rfid


【解决方案1】:

这对我来说似乎是一个范围界定问题;汞库无权访问您列表的内存地址,因此当它调用您的回调函数readTag(e) 时会发生段错误。我认为该库不支持您想要的行为

【讨论】:

  • 这个说法让我觉得很吃惊,但我对汞一无所知。你能详细说明一下吗?
  • 我对水星一无所知,但这里的行为显然是某些底层库(可能用 C 或 Java 编写)调用用户提供的回调函数并且无法访问的结果用户提供的全局范围对象。事实证明,当 OP 退出访问该列表的行时,段错误就会消失。
【解决方案2】:

为了扩展迈克尔的回答,这似乎是范围界定和您正在使用的 API 的问题。一般来说,纯 Python 不会出现段错误。或者至少,它不应该 seg-fault,除非解释器中存在错误,或者您正在使用的某些扩展。这并不是说纯 Python 不会崩溃,只是真正的 seg-fault 表明问题可能是您的代码之外的一些混乱的结果。

我假设您使用的是this Python API

在这种情况下,README.md 提到您使用的 Reader.start_reader() 方法是“异步的”。这意味着它会调用一个新线程或进程并立即返回,然后每次扫描某些内容时后台线程都会继续调用您的回调。

我不太了解 CPython 的细节,无法确切说明发生了什么,但您已将 IDS = [] 声明为全局变量,并且后台线程似乎正在使用不同的上下文运行回调到主程序。因此,当它尝试访问 IDS 时,它正在读取它不拥有的内存,因此会出现 seg-fault。

由于回调的限制性和明显缺乏缓冲区,这可能是开发人员的疏忽。如果您确实需要异步读取,则值得向他们发送问题报告。

否则,考虑到您只是在等待输入,您可能不需要异步读取,您可以在自己的繁忙循环中使用同步 Reader.read() 方法,而不是像这样:

try:
    while True:
        readTags(r.read(timeout=10))
except KeyboardInterrupt: ## break loop on SIGINT (Ctrl-C)
    pass

请注意,r.read() 返回一个标签列表而不仅仅是一个,因此您需要稍微修改您的回调,如果您编写的不仅仅是一个快速脚本,您可能希望使用线程来中断正确循环,因为 SIGINT 非常 hacky。

【讨论】:

    猜你喜欢
    • 2011-04-18
    • 2020-07-30
    • 2013-10-04
    • 1970-01-01
    • 2011-12-20
    • 1970-01-01
    • 1970-01-01
    • 2021-05-18
    • 1970-01-01
    相关资源
    最近更新 更多