ตรวจสอบว่าเธรดปัจจุบันเป็นเธรดหลักหรือไม่


121

มีวิธีใดในการตรวจสอบว่าเธรดปัจจุบันเป็นเธรดหลักใน Objective-C หรือไม่

ฉันอยากทำอะไรแบบนี้

  - (void)someMethod
  {
    if (IS_THIS_MAIN_THREAD?) {
      NSLog(@"ok. this is main thread.");
    } else {
      NSLog(@"don't call this method from other thread!");
    }
  }

มีอะไรผิดปกติเกี่ยวกับการเรียกวิธีการจากเธรดอื่น
David 天宇 Wong

คำตอบ:



24

หากคุณต้องการให้วิธีดำเนินการกับเธรดหลักคุณสามารถ:

- (void)someMethod
{
    dispatch_block_t block = ^{
        // Code for the method goes here
    };

    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_async(dispatch_get_main_queue(), block);
    }
}

5
คำตอบของคำถามเก่าจะได้ประโยชน์จากคำอธิบายว่าคำตอบใหม่แตกต่างจากคำตอบที่มีอยู่อย่างไร
Jason Aller

1
นี่เป็นการใช้งานมากเกินไปหากต้องทำงานบางอย่างในเธรดหลักจะไม่มีประโยชน์ในการตรวจสอบว่าคุณอยู่ในเธรดหลักหรือไม่ Just doNSOperationQueue.mainQueue().addOperationWithBlock { //your work here }
Eric

3
@Eric ฉันเห็นด้วย แต่ถ้าคุณต้องการเรียกใช้เมธอดทันทีหากมีอยู่ในเธรดหลักแล้วล่ะ? ในคำแนะนำของคุณวิธีการจะถูกส่งไปเพื่อดำเนินการในภายหลังผ่านคิวการดำเนินการหลักเสมอ
boherna

@boherna ถูกต้องนั่นคือสิ่งที่ต้องระวัง
Eric

@boherna ความคิดเห็นล่าช้า แต่ประเด็นที่คุณให้ไว้ในความคิดเห็นของคุณจะแข็งแกร่งกว่าถ้าคุณใช้dispatch_sync()แทนdispatch_async()ในตัวอย่างของคุณ
Caleb


13

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

(lldb) thread info

สิ่งนี้จะแสดงข้อมูลเกี่ยวกับเธรดที่คุณอยู่:

(lldb) thread info thread #1: tid = 0xe8ad0, 0x00000001083515a0 MyApp`MyApp.ViewController.sliderMoved (sender=0x00007fd221486340, self=0x00007fd22161c1a0)(ObjectiveC.UISlider) -> () + 112 at ViewController.swift:20, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1

หากค่าqueueเป็นแสดงcom.apple.main-threadว่าคุณอยู่ในเธรดหลัก


6

รูปแบบต่อไปนี้จะทำให้มั่นใจได้ว่ามีการดำเนินการเมธอดบนเธรดหลัก

- (void)yourMethod {
    // make sure this runs on the main thread 
    if (![NSThread isMainThread]) {
        [self performSelectorOnMainThread:_cmd/*@selector(yourMethod)*/
                               withObject:nil
                            waitUntilDone:YES];
        return;
    }
    // put your code for yourMethod here
}

_cmdจะใช้วิธีการวางข้อมูลโค้ดของคุณลงในʕ•ᴥ•ʔโดยอัตโนมัติ
Albert Renshaw

3

สองทาง. จากคำตอบของ @ rano

[[NSThread currentThread] isMainThread] ? NSLog(@"MAIN THREAD") : NSLog(@"NOT MAIN THREAD");

นอกจากนี้

[[NSThread mainThread] isEqual:[NSThread currentThread]] ? NSLog(@"MAIN THREAD") : NSLog(@"NOT MAIN THREAD");

3
void ensureOnMainQueue(void (^block)(void)) {

    if ([[NSOperationQueue currentQueue] isEqual:[NSOperationQueue mainQueue]]) {

        block();

    } else {

        [[NSOperationQueue mainQueue] addOperationWithBlock:^{

            block();

        }];

    }

}

โปรดทราบว่าฉันตรวจสอบคิวการดำเนินการไม่ใช่เธรดเนื่องจากเป็นวิธีการที่ปลอดภัยกว่า


นี่ควรเป็นคำตอบที่ยอมรับได้เธรดหลัก! = คิวหลัก
railwayparade

2

สำหรับ Monotouch / Xamarin iOS คุณสามารถทำการตรวจสอบด้วยวิธีนี้:

if (NSThread.Current.IsMainThread)
{
    DoSomething();
}
else
{
    BeginInvokeOnMainThread(() => DoSomething());
}



0

รายละเอียด

  • Swift 5.1, Xcode 11.3.1

วิธีแก้ไข 1. ตรวจหาคิวใด ๆ

รับ DispatchQueue ปัจจุบันหรือไม่

วิธีแก้ไข 2. ตรวจหาเฉพาะคิวหลัก

import Foundation

extension DispatchQueue {

    private struct QueueReference { weak var queue: DispatchQueue? }

    private static let key: DispatchSpecificKey<QueueReference> = {
        let key = DispatchSpecificKey<QueueReference>()
        let queue = DispatchQueue.main
        queue.setSpecific(key: key, value: QueueReference(queue: queue))
        return key
    }()

    static var isRunningOnMainQueue: Bool { getSpecific(key: key)?.queue == .main }
}

การใช้

if DispatchQueue.isRunningOnMainQueue { ... }

ตัวอย่าง

func test(queue: DispatchQueue) {
    queue.async {
        print("--------------------------------------------------------")
        print("queue label: \(queue.label)")
        print("is running on main queue: \(DispatchQueue.isRunningOnMainQueue)")
    }
}

test(queue: DispatchQueue.main)
sleep(1)
test(queue: DispatchQueue.global(qos: .background))
sleep(1)
test(queue: DispatchQueue.global(qos: .unspecified))

ผลลัพธ์ (บันทึก)

--------------------------------------------------------
queue label: com.apple.root.background-qos
is running on main queue: false
--------------------------------------------------------
queue label: com.apple.root.default-qos
is running on main queue: false
--------------------------------------------------------
queue label: com.apple.main-thread
is running on main queue: true

0
Here is a way to detect what the current queue is
extension DispatchQueue {
    //Label of the current dispatch queue.
    static var currentQueueLabel: String { String(cString: __dispatch_queue_get_label(nil)) }

    /// Whether the current queue is a `NSBackgroundActivityScheduler` task.
    static var isCurrentQueueNSBackgroundActivitySchedulerQueue: Bool { currentQueueLabel.hasPrefix("com.apple.xpc.activity.") }

    /// Whether the current queue is a `Main` task.
    static var isCurrentQueueMainQueue: Bool { currentQueueLabel.hasPrefix("com.apple.main-thread") }
}

-2

UPDATE:ดูเหมือนว่าจะไม่ใช่วิธีแก้ปัญหาที่ถูกต้องตามส่วนหัวของ que.h ตามที่กล่าวไว้ @demosten

ความคิดแรกถูกนำมาสู่ฉันเมื่อฉันต้องการฟังก์ชั่นนี้คือบรรทัด:

dispatch_get_main_queue() == dispatch_get_current_queue();

และได้มองหาวิธีแก้ปัญหาที่ยอมรับแล้ว:

[NSThread isMainThread];

โซลูชันของฉันเร็วขึ้น 2.5 เท่า

ป.ล. และใช่ฉันตรวจสอบแล้วมันใช้ได้กับทุกเธรด


3
มีเหตุผล - วิธีการของคุณข้ามค่าใช้จ่ายของระบบส่งข้อความรันไทม์ obj-c แม้ว่าคุณจะใช้เทคนิคนี้ แต่ฉันก็บอกได้ว่ามันมีกลิ่นรหัสที่ไม่ดีซึ่งอาจเป็นการเพิ่มประสิทธิภาพก่อนเวลาอันควร
ArtOfWarfare

4
dispatch_get_current_queue () เลิกใช้งานจาก
iOs

33
คุณสามารถอ่านสิ่งนี้ในคำอธิบายของส่วนหัว Que.h ของ Apple ที่มีการกำหนด dispatch_get_current_queue (): When dispatch_get_current_queue() is called on the main thread, it may or may not return the same value as dispatch_get_main_queue(). Comparing the two is not a valid way to test whether code is executing on the main thread.
demosten
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.