Merge pull request #32 from petersktang/main

Add NSLock to protect lazily loaded tables in multithread setting
This commit is contained in:
mgriebling
2024-10-26 10:29:53 -04:00
committed by GitHub
2 changed files with 49 additions and 24 deletions

View File

@@ -62,6 +62,7 @@ public class MTMathAtomFactory {
"rfloor" : "\u{230B}" "rfloor" : "\u{230B}"
] ]
private static let delimValueLock = NSLock()
static var _delimValueToName = [String: String]() static var _delimValueToName = [String: String]()
public static var delimValueToName: [String: String] { public static var delimValueToName: [String: String] {
if _delimValueToName.isEmpty { if _delimValueToName.isEmpty {
@@ -78,7 +79,12 @@ public class MTMathAtomFactory {
} }
output[value] = key output[value] = key
} }
_delimValueToName = output // protect lazily loading table in a multi-thread concurrent environment
delimValueLock.lock()
defer { delimValueLock.unlock() }
if _delimValueToName.isEmpty {
_delimValueToName = output
}
} }
return _delimValueToName return _delimValueToName
} }
@@ -98,6 +104,7 @@ public class MTMathAtomFactory {
"widetilde" : "\u{0303}" "widetilde" : "\u{0303}"
] ]
private static let accentValueLock = NSLock()
static var _accentValueToName: [String: String]? = nil static var _accentValueToName: [String: String]? = nil
public static var accentValueToName: [String: String] { public static var accentValueToName: [String: String] {
if _accentValueToName == nil { if _accentValueToName == nil {
@@ -115,7 +122,12 @@ public class MTMathAtomFactory {
} }
output[value] = key output[value] = key
} }
_accentValueToName = output // protect lazily loading table in a multi-thread concurrent environment
accentValueLock.lock()
defer { accentValueLock.unlock() }
if _accentValueToName == nil {
_accentValueToName = output
}
} }
return _accentValueToName! return _accentValueToName!
} }
@@ -390,6 +402,7 @@ public class MTMathAtomFactory {
"scriptscriptstyle" : MTMathStyle(style: .scriptOfScript), "scriptscriptstyle" : MTMathStyle(style: .scriptOfScript),
] ]
private static let textToLatexLock = NSLock()
static var _textToLatexSymbolName: [String: String]? = nil static var _textToLatexSymbolName: [String: String]? = nil
public static var textToLatexSymbolName: [String: String] { public static var textToLatexSymbolName: [String: String] {
get { get {
@@ -413,13 +426,20 @@ public class MTMathAtomFactory {
} }
output[atom.nucleus] = key output[atom.nucleus] = key
} }
self._textToLatexSymbolName = output // protect lazily loading table in a multi-thread concurrent environment
textToLatexLock.lock()
defer { textToLatexLock.unlock() }
if self._textToLatexSymbolName == nil {
self._textToLatexSymbolName = output
}
} }
return self._textToLatexSymbolName! return self._textToLatexSymbolName!
} }
set { // make textToLatexSymbolName readonly (allows internal load)
self._textToLatexSymbolName = newValue // entries can be lazily added with NSLock protection.
} // set {
// self._textToLatexSymbolName = newValue
// }
} }
// public static let sharedInstance = MTMathAtomFactory() // public static let sharedInstance = MTMathAtomFactory()
@@ -603,8 +623,13 @@ public class MTMathAtomFactory {
e.g. to define a symbol for "lcm" one can call: e.g. to define a symbol for "lcm" one can call:
`MTMathAtomFactory.add(latexSymbol:"lcm", value:MTMathAtomFactory.operatorWithName("lcm", limits: false))` */ `MTMathAtomFactory.add(latexSymbol:"lcm", value:MTMathAtomFactory.operatorWithName("lcm", limits: false))` */
public static func add(latexSymbol name: String, value: MTMathAtom) { public static func add(latexSymbol name: String, value: MTMathAtom) {
let _ = Self.textToLatexSymbolName
// above force textToLatexSymbolName to initialise first, _textToLatexSymbolName also initialized.
// protect lazily loading table in a multi-thread concurrent environment
textToLatexLock.lock()
defer { textToLatexLock.unlock() }
supportedLatexSymbols[name] = value supportedLatexSymbols[name] = value
Self.textToLatexSymbolName[value.nucleus] = name Self._textToLatexSymbolName?[value.nucleus] = name
} }
/** Returns a large opertor for the given name. If limits is true, limits are set up on /** Returns a large opertor for the given name. If limits is true, limits are set up on

View File

@@ -47,14 +47,14 @@ final class MTFontMathTableV2Tests: XCTestCase {
func helperConcurrentMTFontMathTableV2(_ count: Int, mtfont: MTFontV2, in group: DispatchGroup, on queue: DispatchQueue) { func helperConcurrentMTFontMathTableV2(_ count: Int, mtfont: MTFontV2, in group: DispatchGroup, on queue: DispatchQueue) {
let workitem = DispatchWorkItem { let workitem = DispatchWorkItem {
let mTable = mtfont.mathTable let mTable = mtfont.mathTable
// let values = [ let values = [
// mTable?.fractionNumeratorDisplayStyleShiftUp, mTable?.fractionNumeratorDisplayStyleShiftUp,
// mTable?.fractionNumeratorShiftUp, mTable?.fractionNumeratorShiftUp,
// mTable?.fractionDenominatorDisplayStyleShiftDown, mTable?.fractionDenominatorDisplayStyleShiftDown,
// mTable?.fractionDenominatorShiftDown, mTable?.fractionDenominatorShiftDown,
// mTable?.fractionNumeratorDisplayStyleGapMin, mTable?.fractionNumeratorDisplayStyleGapMin,
// mTable?.fractionNumeratorGapMin, mTable?.fractionNumeratorGapMin,
// ].compactMap{$0} ].compactMap{$0}
// if count % 50 == 0 { // if count % 50 == 0 {
// print(values) // accessed these values on global thread. // print(values) // accessed these values on global thread.
// } // }
@@ -62,16 +62,16 @@ final class MTFontMathTableV2Tests: XCTestCase {
} }
workitem.notify(queue: .main) { [weak self] in workitem.notify(queue: .main) { [weak self] in
// print("\(Thread.isMainThread ? "main" : "global") completed .....") // print("\(Thread.isMainThread ? "main" : "global") completed .....")
// let mTable = mtfont.mathTable let mTable = mtfont.mathTable
if count % 70 == 0 { if count % 70 == 0 {
// let values = [ let values = [
// mTable?.fractionNumeratorDisplayStyleShiftUp, mTable?.fractionNumeratorDisplayStyleShiftUp,
// mTable?.fractionNumeratorShiftUp, mTable?.fractionNumeratorShiftUp,
// mTable?.fractionDenominatorDisplayStyleShiftDown, mTable?.fractionDenominatorDisplayStyleShiftDown,
// mTable?.fractionDenominatorShiftDown, mTable?.fractionDenominatorShiftDown,
// mTable?.fractionNumeratorDisplayStyleGapMin, mTable?.fractionNumeratorDisplayStyleGapMin,
// mTable?.fractionNumeratorGapMin, mTable?.fractionNumeratorGapMin,
// ].compactMap{$0} ].compactMap{$0}
// if count % 50 == 0 { // if count % 50 == 0 {
// print(values) // print(values)
// } // }