การใช้ @synchronized กับการดำเนินการแบบซิงโครนัส

ฉันกำลังใช้คลาสย่อย UIDocument ที่มีศักยภาพมีเมธอด saveToURL ที่ถูกเรียกจากมากกว่าหนึ่งเธรด ดังนั้นฉันจึงสรุปมันไว้ในฟังก์ชัน wrapper ซึ่งฉันต้องการทำให้เธรดปลอดภัย:

- (void)saveWithCompletionBlock:(void(^)(TransactionDocumentReturnCode status))completion {
    @synchronized (self) {
        [self saveToURL:[self fileURL] forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success){
            // Generate returncode depending on outcome of save operation
            completion(returncode);
        }];
    }
}

ฉันสมมติว่าการเรียก [self saveToURL:...] จะกลับมาทันทีเนื่องจากการดำเนินการบันทึกนั้นเกิดขึ้นบนเธรดพื้นหลัง ส่งผลให้การล็อกถูกปล่อยก่อนที่การดำเนินการบันทึกจะเสร็จสิ้น ดังนั้น มีวิธีใดที่จะทำให้เธรดอื่นที่เรียก saveWithCompletionBlock: ถูกบล็อกจนกว่าจะมีการเรียกบล็อกที่สมบูรณ์ของ saveToURL หรือไม่


person mashers    schedule 25.03.2016    source แหล่งที่มา
comment
ดูคำตอบนี้สำหรับสองวิธีในการใช้งาน: stackoverflow.com/a/7649768/78496   -  person chedabob    schedule 25.03.2016
comment
ขอบคุณ @chedabob ครับ การใช้ GCD หรือ NSOperationQueue จะส่งผลให้การเรียกฟังก์ชัน save wrapper ในภายหลังถูกบล็อกจนกว่าบล็อกการดำเนินการบันทึกจะเสร็จสิ้นหรือไม่   -  person mashers    schedule 25.03.2016


คำตอบ (1)


วิธีแก้ปัญหาที่เป็นไปได้อย่างหนึ่งที่ฉันเพิ่งคิดคือการเพิ่มคุณสมบัติให้กับคลาสย่อย UIDocument ของฉันเพื่อระบุว่าการดำเนินการบันทึกกำลังดำเนินการอยู่หรือไม่ และหากเป็นเช่นนั้น ให้รอแล้วลองอีกครั้ง การล้อมการตรวจสอบและการตั้งค่าคุณสมบัตินี้ใน @synchronize ควรป้องกันไม่ให้เธรดสองเธรดอ่านค่าเป็นเท็จพร้อมกันและเชื่อว่าสามารถบันทึกเอกสารได้:

- (void)saveWithCompletionBlock:(void(^)(TransactionDocumentReturnCode status))completion {
    @synchronized(self){
        if (self.isSaving) {
            [self performSelector:@selector(saveWithCompletionBlock:) withObject:completion afterDelay:1.0];
            return;
        }

        self.isSaving = YES;
    }

    [self saveToURL:[self fileURL] forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success){
        // Generate returncode depending on outcome of save operation
        completion(returncode);
        self.isSaving = NO;
    }];
}

ฉันไม่รู้ว่านี่จะเพียงพอหรือถือว่าเป็นการฝึกแบบมัลติเธรดที่ดีหรือไม่

person mashers    schedule 25.03.2016
comment
วิธีแก้ปัญหาข้างต้นดูเหมือนว่าจะทำงานได้ดี การเพิ่มการเรียกไปที่ [NSObject cancelPreviousPerformRequestsWithTarget:self] ก่อน [self performSelector:...] ทำให้แอปต้องรอจนกระทั่งสิ้นสุดการดำเนินการบันทึกครั้งแรก จากนั้นจึงบันทึกอีกครั้งหลังจากเสร็จสิ้น ฉันยังคงยินดีรับข้อเสนอแนะเกี่ยวกับโซลูชันนี้ - person mashers; 25.03.2016