/ / ObjectiveC - Vyhnúť sa zablokovaniu pri synchrónnom odosielaní do hlavnej fronty z pozadia - objektív-c, multithreading, súbežnosť, synchronizácia, grand-central-dispatch

Cieľ C - Vyhnúť sa zablokovaniu pri synchronizovanom odosielaní do hlavnej fronty z pozadia - objektív-c, multithreading, súbežnosť, synchronizácia, grand-central-dispatch

Nedávno som sa dostal do bodu, keď som potreboval nejakéblok kódu vykonať vždy na hlavnom vlákne synchrónne. Tento blok je možné zavolať z ľubovoľného vlákna. Tento problém som vyriešil kódom, ktorý už bol navrhnutý v tomto Tak odpovedzte @Brad Larson

Ako poznámky k tejto odpovedi je zrejmé, že môže dôjsť k zablokovaniu, ale veľmi ľahko som sa dostal do mŕtveho bodu. Pozrite si tento kód.

-(IBAction) buttonClicked
{
// Dispatch on the global concurrent queue async.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSString* data =  [self getTheString];
NSLog(@"From Background Thread: %@", data);
};

// Dispatch on the main queue async.
dispatch_async(dispatch_get_main_queue(), ^{
NSString* data = [self getTheString];
NSLog(@"From Main Thread: %@", data);
};
}

// This method can be called from any thread so synchronize it.
// Also the code that sets the string variable based on some logic need to execute on main thread.

-(NSString*) getTheString
{
__block NSString* data = nil;
@synchronized(self)
{
// Have some code here that need to be synchronized between threads.
// .......
//

// Create a block to be executed on the main thread.

void (^blockToBeRunOnMainThread)(void) = ^{
// This is just a sample.
// Determining the actual string value can be more complex.
data = @"Tarun";
};

[self dispatchOnMainThreadSynchronously:blockToBeRunOnMainThread];
}
}

- (void) dispatchOnMainThreadSynchronously:(void(^)(void))block
{
if([NSThread isMainThread])
{
if (block)
{
block();
}
}
else
{
dispatch_sync(dispatch_get_main_queue(), ^{
if (block)
{
block();
}
});
}
}

V tomto kóde sú dva simultánne asynchrónne požiadavky na funkciu getTheString (Predpokladajme, že nemáte žiadnu kontrolu nad metódou buttonKlicked a ako volá getTheString api). Predpokladajme, že požiadavka z globálnej fronty prichádza prvý a pokúša sa spustiť blok na hlavnom vlákne synchrónne, až do tej doby pozadie na pozadí čaká na hlavné vlákno na vykonanie bloku synchrónne, súčasne požiadavka z hlavnej fronty prichádza a skúša získať zámok z pozadia vlákna, ale ako pozadie na pozadí v neúplné hlavné vlákno čaká na závit na dokončenie. Tu máme zablokovanie hlavného vlákna ako hlavného vlákna, ktoré čaká na ukončenie pozadia vlákna a závit na pozadí čaká na vykonanie bloku hlavného vlákna.

Ak odstránim príkaz @synchronize všetkofunguje podľa očakávania. Možno nemusím tu @ synchronize vyhlásenie tu, ale v tom istom prípade budete musieť mať to, alebo sa to môže stať aj z niektorých ďalších častí kódu.

Snažil som sa hľadať celú sieť pre riešenie a tiež sa pokúsil dispatch_semaphore, ale problém sa nepodarilo vyriešiť. Možno, že jednoducho nerobím veci správnym smerom.

Predpokladám, že je to klasický problém zablokovania, ktorým sa znovu a znovu stretávajú vývojári a pravdepodobne to do istej miery vyriešili. Môže s tým niekto pomôcť, alebo mi ukazovať správnym smerom?

odpovede:

1 pre odpoveď č. 1

Vytvoril by som synchrónny rad (NSOperationQueue by bolo najjednoduchšie) a predložiť blok, ktorý má byť spustenýna hlavnom vlákne do tejto fronty. Riadok bude odosielať bloky v prijatom poradí, pričom zachová objednávku, ktorú si želáte. Súčasne oddeľuje synchronicitu medzi volaním getTheString a odoslanie do hlavného vlákna.