У меня есть функция, которая возвращает использование памяти устройства. Он использует mach_task_self_, который предупреждает, что он небезопасен для параллелизма.
task_info(mach_task_self_, task_flavor_t(TASK_VM_INFO), intPtr, &count)
Согласно этому ответу вы можете импортировать и пометить как @preconcurrency, однако когда я попробовал это, это не сработало.
@preconcurrency import Darwin.Mach.mach_init
Там написано '@preconcurrency' attribute on module 'Darwin' has no effect
Когда я перехожу к определению mach_task_self_, я вижу, что оно находится в Darwin > Mach > mach_init.





Похоже, что @preconcurrency import не будет работать, если вещь, к которой вы пытаетесь получить доступ, также импортирована с помощью другого импорта без предварительного параллелизма. Вероятно, вы также импортируете такие вещи, как Foundation.
Если вы поместите импорт в отдельный файл,
@preconcurrency import Darwin
var machTaskSelf: mach_port_t {
mach_task_self_
}
нет никакого предупреждения.
И теперь вы можете использовать это вычисленное свойство в другом месте.
task_info(machTaskSelf, task_flavor_t(TASK_VM_INFO), intPtr, &count)
Странный. Он делает это как в моей основной структуре, так и в небольшом тестовом приложении, которое я создал специально для этого здесь file.io/LyHve5khA1bt Я также пробовал новый Xcode и Swift 6, но он тот же.
Да! Я действовал на автопилоте и даже не заметил этого. Спасибо.
Собственно, хотя в новом тестовом проекте это работает. Он по-прежнему выдает мне ошибки в моем основном проекте Framework. В новом файле есть только импорт preconcurrency и переменная machTaskSelf, но я получаю сообщение об ошибке, связанное с отсутствием эффекта предварительного параллелизма. Может ли это быть связано с порядком компиляции файлов?
@Даррен Хорошо, мне удалось воспроизвести это в проекте SPM (в отличие от проекта Xcode). Согласно это, «импорт из других языков осуществляется неявно @preconcurrency», поэтому вы можете просто удалить @preconcurrency. Поэтому я предполагаю, что, по-видимому, Darwin считается «из другого языка» в проекте SPM, но не в проекте Xcode.
Интересный. Однако удаление pre concurrency по-прежнему приводит к фактическому mach_task_self_ сообщению, что он небезопасен для параллелизма.
Интересно, что если полностью удалить import Darwin и оставить в файле только machTaskSelf var, проект компилируется нормально. Значит, он, должно быть, импортирует его откуда-то еще.
@Даррен, почему ты не принял? Насколько я вижу из вашего последнего комментария, ваша проблема решена. Если вы тоже хотите, чтобы я объяснил, откуда импортирован mach_task_self_? Это другой вопрос, и вам нужно будет показать минимально воспроизводимый пример.
Извините, я не знал, что могу не принять. Моя проблема не решена. Сам проект находится здесь github.com/ddaddy/DJLogging-Swift и использование вашего решения приводит к ошибке компилятора при использовании Swift 6, чего я пытаюсь избежать.
Я вижу замешательство. Мой комментарий по поводу компиляции проекта просто указывал на то, что мне вообще не нужен импорт. Он по-прежнему быстро предупреждает, что mach_task_self_ небезопасен для параллелизма.
@Даррен, я понимаю. Я думаю, что понять, почему вам не нужен импорт для Дарвина, — это хороший первый шаг. После того, как вы это выясните, попробуйте сделать так, чтобы вам действительно требовался импорт. Тогда импорт @preconcurrency, вероятно, сработает. Это все, что я хочу сказать.
Понятно :) Поскольку Framework поддерживает objc, у него есть публичный заголовок, который импортирует Foundation. Удаление удалило предупреждение. Спасибо.
Мне отлично помогло и с другими mach проблемами: @preconcurrency import Darwin var vm_kernel_page_size: vm_size_t { Darwin.vm_kernel_page_size }
Ранее сегодня я столкнулся с той же проблемой и в итоге нашел обходной путь, чтобы избавиться от предупреждений.
Мне пришлось немного побаловаться с Objective-C, но это позволило мне написать оболочку для mach_task_self_, которая заимствует изоляцию актеров Swift, чтобы мы могли безопасно получать доступ к данным.
Я создал класс со статическим свойством, которое инициализируется сразу после загрузки фреймворка, и все последующие обращения к атрибуту синхронизируются внутри. В моем случае это прекрасно сработало, надеюсь, вам это тоже поможет!
MyMachTaskWrapper.h:
@import Foundation;
@import Darwin;
__attribute__((swift_attr("@MainActor")))
@interface MyMachTaskWrapper: NSObject
@property(class) mach_port_t isolatedMachTaskSelf;
@end
MyMachTaskWrapper.m:
#import "MyMachTaskWrapper.h"
@implementation MyMachTaskWrapper
static mach_port_t isolated_mach_task_self_;
// Invoked when this class is added to the Objective-C runtime
+ (void)load {
[self setIsolatedMachTaskSelf:mach_task_self_];
}
// Just to be sure I decided to synchronize reads with a mutex lock,
// but I'm not completely sure if this is needed
+ (mach_port_t)isolatedMachTaskSelf {
@synchronized(self) {
return isolated_mach_task_self_;
}
}
// This should only ever run on `load`
+ (void)setIsolatedMachTaskSelf:(mach_port_t)task {
isolated_mach_task_self_ = task;
}
@end
Конечно, вам нужно будет предоставить этот класс Swift. После этого использование будет таким же простым, как:
Task { @MainActor in
MyMachTaskWrapper.isolatedMachTaskSelf // no warnings here!
}
Обратите внимание, что Swift воспринимает MyMachTaskWrapper как @MainActor, поэтому мы должны убедиться, что работаем в правильном контексте.
Идея написать эту обертку пришла мне от SE-0412, в которой говорится:
Остаются инструменты для обеспечения безопасности импортированных глобальных переменных из других языков, такие как изоляция глобального актера с использованием, например, атрибута((swift_attr("@MainActor"))) в C или Obj-C или перенос доступа в более безопасный API. который объявляет правильную изоляцию или блокирует соответствующим образом.
Я до сих пор не уверен, что это лучший подход, но у меня он работает :)
Спасибо. Я только что попробовал это, но получаю сообщение об ошибке «Использование заголовков моста с целями платформы не поддерживается», поэтому я думаю, что смешивание objc и Swift может быть здесь не лучшей идеей.
@Даррен, взгляни на эту ссылку?. Вам придется предпринять дополнительные шаги, чтобы заставить его работать для целей платформы, но это наверняка возможно! Я знаю, потому что делал это раньше :) Вам просто нужно придумать заголовок зонтика, и все готово.
Несмотря на то, что это удаляет предупреждение об импорте
@preconcurrency, оно все равно выдает предупреждение о том, чтоmach_task_self_небезопасен для параллелизма.