Estou desenvolvendo framework iOS com Objective-C.
Eu crio um dispatch_queue_t
usando dispatch_queue_create
. E ligue CFRunLoopRun()
para executar o runloop na fila.
Mas, parece que o dispatch_queue_t compartilhou o RunLoop. Algumas classes adicionaram um cronômetro inválido e, quando eu chamo o CFRunLoopRun()
, ele travou do meu lado.
- (void)viewDidLoad {
[super viewDidLoad];
self.queue1 = dispatch_queue_create("com.queue1", DISPATCH_QUEUE_CONCURRENT);
self.queue2 = dispatch_queue_create("org.queue2", DISPATCH_QUEUE_CONCURRENT);
}
- (IBAction)btnButtonAction:(id)sender {
dispatch_async(self.queue1, ^{
NSString *runloop = [NSString stringWithFormat:@"%@", CFRunLoopGetCurrent()];
runloop = [runloop substringWithRange:NSMakeRange(0, 22)];
NSLog(@"Queue1 %p run: %@", self.queue1, runloop);
//NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate date] interval:1 target:self selector:@selector(wrongSeletor:) userInfo:nil repeats:NO];
//[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
});
dispatch_async(self.queue2, ^{
NSString *runloop = [NSString stringWithFormat:@"%@", CFRunLoopGetCurrent()];
runloop = [runloop substringWithRange:NSMakeRange(0, 22)];
NSLog(@"Queue2 %p run: %@", self.queue2, runloop);
CFRunLoopRun();
});
}
Algum tempo eles levam o mesmo RunLoop:
https://isstatic.askoverflow.dev/wGcv3.png
=====
Você pode ver a falha descomentando o código de NSTimer
. O NSTimer foi adicionado queue1
, mas ainda está em execução quando CFRunLoopRun()
chamado queue2
.
Eu li algumas descrições como: preciso de alguns esclarecimentos sobre fila de despacho, thread e NSRunLoop
Eles contaram que: system creates a run loop for the thread
. Mas, na minha opinião, eles estão compartilhando o RunLoop.
Isso é triste para mim, pois enfrento que acontecem travamentos ao chamar CFRunLoopRun()
a produção.
dr.
Existem vários problemas com esse código de loop de execução. Mas, se a intenção fosse simplesmente executar um cronômetro em uma fila de despacho, geralmente usaríamos um cronômetro de origem de despacho , eliminando grande parte dessa confusão.
O padrão de loop de execução típico envolve a criação de um thread dedicado, a obtenção de um loop de execução para esse thread e a chamada de um dos métodos de “execução” para girar nesse thread, processando eventos de loop de execução, como eventos de timer.
Uma fila de despacho é uma abordagem diferente. Quando despachamos um “item de trabalho” para uma fila de despacho, essa fila buscará um thread de trabalho (aleatório) de um conjunto de threads, executará esse item de trabalho naquele thread de trabalho e, quando o item de trabalho estiver concluído, retornará esse item de trabalho thread para o pool de threads, disponibilizando-o para despachos futuros.
Isso nos leva a várias observações sobre seu snippet de código:
O envio para
queue1
não faz sentido. Você imprime um loop de execução, mas não “executa” nele, apenas finaliza, retornando assim o thread de trabalho ao pool de threads. Esse tópico agora está disponível para ser usado novamente em futuros despachos do GCD. Só faria sentido se você girasse nesse loop de execução com um método “run”, vinculando assim esse thread a esse loop de execução e evitando que o GCD reutilizasse esse thread.Usar uma fila simultânea neste contexto é confuso. Execute loops girando em um determinado thread. Criar uma fila simultânea para essa finalidade não faz sentido. Que trabalho será feito simultaneamente nessa fila enquanto o loop de execução gira em um dos threads de trabalho? Isso sugere um mal-entendido conceitual sobre como funcionam os loops de execução.
A ideia de girar indefinidamente em um loop de execução em um thread de trabalho GCD é, de todo, imprudente. O conceito geral das filas de despacho é que elas alcançam eficiência buscando um thread de trabalho existente no pool, executando o item de trabalho e retornando esse thread ao pool. A ideia de amarrar indefinidamente um thread de trabalho é indiscutivelmente antitética à ideia motivadora por trás do GCD. Você pode fazer isso, mas geralmente evitaríamos amarrar um thread de trabalho do GCD indefinidamente.
Se você estiver academicamente interessado em como funcionam os loops de execução, esta exploração é adequada. Mas se você pretendia apenas executar um cronômetro em uma fila de despacho, execute loops e
NSTimer
essa é a abordagem errada. Um temporizador de despacho seria muito mais simples (veja abaixo).Se você quiser executar algo em uma fila de despacho, geralmente não usamos
NSTimer
. Em vez disso, usaríamos um temporizador de despacho. Isso não requer nenhum loop de execução.Ao contrário de a,
NSTimer
precisamos manter nossa referência forte ao cronômetro:Então, para iniciar um cronômetro:
Para parar o cronômetro, solte-o: