使用Zig的@fieldParentPtr时触发死锁检测错误的解决
在Zig中模拟接口行为时的死锁问题及解决方法
我尝试在Zig语言中通过技巧实现接口行为,编写示例代码期望调用Animal结构体的函数时访问Dog结构体的属性。虽然能成功获取name属性的值,但在std.debug.print中使用该值时触发了死锁检测错误。
错误信息片段
thread 17672 panic: Deadlock detected C:\Software\Zig\Zig12Dev\zig\lib\std\Thread\Mutex.zig:45:19: 0xde2de4 in lock (zoo_example.exe.obj) self.impl.lock(); ^ C:\Software\Zig\Zig12Dev\zig\lib\std\debug.zig:85:22: 0xde34cb in print__anon_7068 (zoo_example.exe.obj) stderr_mutex.lock(); ^ C:\Software\Zig\Zig12Dev\zig\lib\std\os\windows.zig:2688:24: 0xdb234f in unexpectedError (zoo_example.exe.obj) std.debug.print("error.Unexpected: GetLastError({}): {}\n", .{ .... ....
原问题代码
const std = @import("std"); const Animal = struct{ walkfn : *const fn(*const Animal,u32) anyerror!void, fn walk(self:*const Animal,speed:u32) !void{ return self.walkfn(self,speed); } }; const Dog = struct{ animal:Animal = Animal{.walkfn = walk}, name:[]const u8, fn walk(animal:*const Animal,speed:u32) !void{ const self = @fieldParentPtr(Dog,"animal",animal); const _name = self.name; std.debug.print("{s} is walking with {d} miles/hr\n",.{_name,speed}); } }; const Cat = struct{ animal:Animal = Animal{.walkfn = walk}, fn walk(_:*const Animal,speed:u32) !void{ std.debug.print("cat is walking with {d} miles/hr\n",.{speed}); } }; pub fn main() !void{ const animals:[2]Animal = [_]Animal{(Dog{.name="Buddy"}).animal,(Cat{}).animal}; for (animals) |animal|{ try animal.walk(12); } }
问题原因及解决方案
原代码的核心问题在于:创建animals数组时,Dog{.name="Buddy"}是临时值,其生命周期仅存在于数组初始化的瞬间,后续访问该临时值的属性会导致未定义行为,进而触发死锁。
正确的实现方式是通过*anyopaque存储具体类型的指针,同时保证具体实例的生命周期覆盖整个使用过程。以下是可行的解决方案代码:
const std = @import("std"); const Animal = struct{ ptr: *anyopaque, walkfn: *const fn(ptr:*anyopaque,speed:u32) anyerror!void, fn walk(animal:Animal,speed:u32) !void{ try animal.walkfn(animal.ptr,speed); } }; const Dog = struct{ age:u32, fn walk(ptr:*anyopaque,speed:u32) !void{ const self:*Dog = @ptrCast(@alignCast(ptr)); std.debug.print("dog is {d} years old and is walking with speed {d}\n",.{self.age,speed}); } fn animal(self:*Dog) Animal{ return .{.ptr = self, .walkfn = walk}; } }; const Cat = struct{ color:[]const u8, fn walk(ptr:*anyopaque,speed:u32) !void{ const self:*Cat = @ptrCast(@alignCast(ptr)); std.debug.print("cat with color {s} is walking with speed {d}\n",.{self.color,speed}); } fn animal(self:*Cat) Animal{ return .{.ptr = self,.walkfn = walk}; } }; const AnimalWalker = struct{ fn walk(animal:Animal) !void{ try animal.walk(20); } }; pub fn main() !void{ var dog = Dog{.age=12}; var cat = Cat{.color="grey"}; const animals:[2]Animal = [_]Animal{dog.animal(),cat.animal()}; for (animals) |animal|{ try animal.walk(123); } }
内容的提问来源于stack exchange,提问作者gmcoding
相关产品推荐
相关产品推荐

