for (int s=0; s<masterArray.count; s++) {
for (int i=0; i<countOfSub1; i++) {
}
}
vast amount of data in this loop so, i want get when s=0 then get all data of second loop then after s=1 then after get all data of second loop so on, then how can i set thread in this code. Thanks.
You can use it by the following example
for (int s=0; s<masterArray.count; s++) {// your main loop starts here
dispatch_semaphore_t sem;
sem = dispatch_semaphore_create(0);
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
for (int i=0; i<countOfSub1; i++) {// Inner loop in a thread
//your work here
}
dispatch_semaphore_signal(sem);
});
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); // main loop waiting to be triggered from sub loop. (inner loop)
}
Related
I think "end" will be print in for loop, but this is wrong, can you tell me why. This is code:
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
for (NSUInteger i = 0; i < 1000; i++) {
dispatch_async(queue, ^{
NSLog(#"i:%lu", (unsigned long)i);
});
}
dispatch_async(queue, ^{
NSLog(#"end:%#", [NSThread currentThread]);
});
Result:
2018-03-22 19:26:33.812371+0800 MyIOSNote[96704:912772] i:990
2018-03-22 19:26:33.812671+0800 MyIOSNote[96704:912801] i:991
2018-03-22 19:26:33.812935+0800 MyIOSNote[96704:912662] i:992
2018-03-22 19:26:33.813295+0800 MyIOSNote[96704:912802] i:993
2018-03-22 19:26:33.813552+0800 MyIOSNote[96704:912766] i:994
2018-03-22 19:26:33.813856+0800 MyIOSNote[96704:912778] i:995
2018-03-22 19:26:33.814299+0800 MyIOSNote[96704:912803] i:996
2018-03-22 19:26:33.814648+0800 MyIOSNote[96704:912779] i:997
2018-03-22 19:26:33.814930+0800 MyIOSNote[96704:912759] i:998
2018-03-22 19:26:33.815361+0800 MyIOSNote[96704:912804] i:999
2018-03-22 19:26:33.815799+0800 MyIOSNote[96704:912805] end:<NSThread: 0x60400027e200>{number = 3, name = (null)}
Look at the order of execution. You first enqueue 1000 blocks to print a number. Then you enqueue the block to print "end". All of those blocks are enqueued to run asynchronously on the same concurrent background queue. All 1001 calls to dispatch_async are being done in order, one at a time, on whatever thread this code is being run on which is from a different queue all of the enqueued blocks will be run on.
The concurrent queue will pop each block in the order it was enqueued and run it. Since it is a concurrent queue and since each is to be run asynchronously, in theory, some of them could be a bit out of order. But in general, the output will appear in the same order because each block does exactly the same thing - a simple NSLog statement.
But the short answer is that "end" is printed last because it was enqueued last, after all of the other blocks have been enqueued.
What may help is to log each call as it is enqueued:
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
for (NSUInteger i = 0; i < 1000; i++) {
NSLog(#"enqueue i: %lu", (unsigned long)i);
dispatch_async(queue, ^{
NSLog(#"run i: %lu", (unsigned long)i);
});
}
NSLog(#"enqueue end");
dispatch_async(queue, ^{
NSLog(#"run end: %#", [NSThread currentThread]);
});
For loop code runs in main Queue (Serial) so the for loop ends then the end statement is printed , if you wrapped the for loop inside the async like this
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
for (NSUInteger i = 0; i < 1000; i++) {
NSLog(#"i:%lu", (unsigned long)i);
}
});
dispatch_async(queue, ^{
NSLog(#"end:%#", [NSThread currentThread]);
});
you will get this
To combine both of the previous answers, the reason you see end printed last is because you enqueue serially, but each block executes very quickly. By the time you enqueue the log of end, all the other blocks have already executed.
I've some data which is accumulated in a buffer and I need to read the data when buffer is having data. This i need to do with thread synchronisation. I've worked little with GCD, which I'm failing to do. please help how to do a circular buffer with read and write threads in synchronization.
My Code:
- (void)viewDidLoad {
[super viewDidLoad];
readPtr = 0;
writePtr = 0;
currentPtr = 0;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{
while(YES){
[self writeToBuffer:buffer[0] withBufferSize:bufferSize];
}
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{
while(YES){
float* newBuffer;
if(currentPtr>512){
newBuffer = [self readBuffer];
}else{
continue;
}
[self UseBuffer: newBuffer];
}
});
}
-(void)writeToBuffer:(float*)Values withBufferSize:(int)bSize{
[_lock lock];
for(int i=0;i<bSize;i++){
if(writePtr>1859){
writePtr = 0;
}
globalBuffer[writePtr] = Values[i];
writePtr++;
currentPtr++;
}
NSLog(#"Writing");
[_lock unlock];
}
-(float*)readBuffer{
[_lock lock];
float rBuffer[512];
for(int i=0;i<512;i++){
if(readPtr>1859){
readPtr = 0;
}
rBuffer[i] = globalBuffer[readPtr];
readPtr++;
currentPtr--;
}
NSLog(#"Reading");
[_lock unlock]
return rBuffer;
}
One of the key points of GCD is that it completely replaces the need for locks. So, if you are mixing GCD and mutex locks it is typically a sign that you're doing things wrong or sub-optimally.
A serial queue is, effectively, an exclusive lock on whatever is associated with the serial queue.
There a bunch of problems in your code.
while (YES) {...} is going to spin, burning CPU cycles ad infinitum.
The readBuffer method is returning a pointer to a stack based buffer. That won't work.
It isn't really clear what the goal of the code is, but those are some specific issues.
So with some help, I am more clear on how a nested GCD works in my program.
The original post is at:
Making sure I'm explaining nested GCD correctly
However, you don't need to go through the original post, but basically the code here runs database execution in the background and the UI is responsive:
-(void)viewDidLoad {
dispatch_queue_t concurrencyQueue = dispatch_queue_create("com.epam.halo.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t serialQueue = dispatch_queue_create("com.epam.halo.queue2", DISPATCH_QUEUE_SERIAL);
for ( int i = 0; i < 10; i++) {
dispatch_async(concurrencyQueue, ^() {
NSLog(#"START insertion method%d <--", i);
dispatch_sync(serialQueue, ^() {
//this is to simulate writing to database
NSLog(#"----------START %d---------", i);
[NSThread sleepForTimeInterval:1.0f];
NSLog(#"--------FINISHED %d--------", i);
});
NSLog(#"END insertion method%d <--", i);
});
}
}
However, when I start refactoring them and putting them into methods and making everything look nice, the UI does not respond anymore:
//some database singleton class
//the serial queues are declared in the class's private extension. And created in init()
-(void)executeDatabaseStuff:(int)i {
dispatch_sync(serialQueue, ^() {
//this is to simulate writing to database
NSLog(#"----------START--------- %d", i);
[NSThread sleepForTimeInterval:1.0f];
NSLog(#"--------FINISHED-------- %d", i);
});
}
-(void)testInsert:(int)i {
dispatch_async(concurrencyQueue, ^() {
[self executeDatabaseStuff:i];
});
}
//ViewController.m
- (void)viewDidLoad {
//UI is unresponsive :(
for ( int i = 0; i < totalNumberOfPortfolios; i++) {
NSLog(#"START insertion method%d <--", i);
[[DatabaseFunctions sharedDatabaseFunctions] testInsert: i];
NSLog(#"END insertion method%d <--", i);
}
}
The only way to make the refactored version work is when I put dispatch_async(dispatch_get_main_queue():
for ( int i = 0; i < totalNumberOfPortfolios; i++) {
dispatch_async(dispatch_get_main_queue(), ^() {
NSLog(#"START insertion method%d <--", i);
[[DatabaseFunctions sharedDatabaseFunctions] testInsert: i];
NSLog(#"END insertion method%d <--", i);
});
}
So my question is, I thought the fact that I use dispatch_async the concurrencyQueue will ensure that my main thread is not touched by the dispatch_sync serialQueue combo. Why is it that when I wrap it in an object/method, I must use dispatch_async(dispatch_get_main_queue()...) ?
Seems that whether my main thread does dispatch_async on a concurrent queue
in viewDidLoad, or within a method, does indeed matter.
I am thinking that the main thread is getting all these testInsert methods pushed onto its thread stack. The methods must then be processed by the main thread. Hence, even though the dispatch_sync is not blocking the main thread, the main thread runs to the end of viewDidLoad, and must wait for all the testInsert methods to be processed and done before it can move onto the next task in the Main Queue??
Notes
So I went home and tested it again with this:
for ( int i = 0; i < 80; i++) {
NSLog(#"main thread %d <-- ", i);
dispatch_async(concurrencyQueue, ^() {
[NSThread isMainThread] ? NSLog(#"its the main thread") : NSLog(#"not main thread");
NSLog(#"concurrent Q thread %i <--", i);
dispatch_sync(serialQueue, ^() {
//this is to simulate writing to database
NSLog(#"serial Q thread ----------START %d---------", i);
[NSThread sleepForTimeInterval:1.0f];
NSLog(#"serial Q thread --------FINISHED %d--------", i);
});
NSLog(#"concurrent Q thread %i -->", i);
});
NSLog(#"main thread %d --> ", i);
} //for loop
When I run the loop from 1 - 63, the UI is not blocked. And I see my database operation processing in the background.
Then when the loop is 64, UI is blocked for 1 database operation, then returns fine.
When I use 65, UI freezes for 2 database operations, then returns fine...
When I use something like 80, it gets blocked from 64-80...so I wait 16 seconds before my UI is responsive.
At the time, I couldn't figure out why 64. So now I know that its 64 concurrent threads allowed at once. ...and has nothing to do with wrapping it in a object/method. :D
Many thanks for the awesome help from the contributors!
There is a hard limit of 64 GCD concurrent operations (per top level concurrent queue) that can be run together.
What's happening is you're submitting over 64 blocks to your concurrent queue, each of them getting blocked by the [NSThread sleepForTimeInterval:1.0f], forcing a new thread to be created for each operation. Therefore, once the thread limit is reached, it backs up and starts to block the main thread.
I have tested this with 100 "database write" operations (on device), and the main thread appears to be blocked until 36 operations have taken place (there are now only 64 operations left, therefore the main thread is now un-blocked).
The use of a singleton shouldn't cause you any problems, as you're calling methods to that synchronously, therefore there shouldn't be thread conflicts.
The simplest solution to this is just to use a single background serial queue for your "database write" operations. This way, only one thread is being created to handle the operation.
- (void)viewDidLoad {
[super viewDidLoad];
static dispatch_once_t t;
dispatch_once(&t, ^{
serialQueue = dispatch_queue_create("com.epam.halo.queue2", DISPATCH_QUEUE_SERIAL);
});
for (int i = 0; i < 100; i++) {
[self testInsert:i];
}
}
-(void)executeDatabaseStuff:(int)i {
//this is to simulate writing to database
NSLog(#"----------START--------- %d", i);
[NSThread sleepForTimeInterval:1.0f];
NSLog(#"--------FINISHED-------- %d", i);
}
-(void)testInsert:(int)i {
NSLog(#"Start insert.... %d", i);
dispatch_async(serialQueue, ^() {
[self executeDatabaseStuff:i];
});
NSLog(#"End insert... %d", i);
}
I don't know why inserting dispatch_async(dispatch_get_main_queue(), ^() {} inside your for loop was working for you... I can only assume it was off-loading the "database writing" until after the interface had loaded.
Further resources on threads & GCD
Number of threads created by GCD?
https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW1
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html#//apple_ref/doc/uid/10000057i-CH15-SW2
Is there any way to notify when a enumerateLinesUsingBlock is completed? Please check below code. I am calling createFastSearchData method with chunk by chunk data in a while loop and inside that taking each lines and processing it. In while condition I am checking the length of the main string and I want to continue untill it completes the total length. So I want to make sure that enumerateLinesUsingBlock is completed before the while loop trigger again.
while(<checking the length of the mainstring>){
[self createFastSearchData:string];
}
- (void)createFastSearchData:(NSString *)newChunk{
[newChunk enumerateLinesUsingBlock:^(NSString * line, BOOL * stop)
{}];
}
Added:
I am working with blocks and finding difficulty to understand the actual flow. Please check the below code. I want to call fetchCSVData method by passing different values in an array filesToBeFetchedWhat. I want to make sure that, fetchCSVData should not overlap. How can I do that? Please help
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
#autoreleasepool {
for (int i = 0; i < filesToBeFetched.count; i++) {
[applicationDelegate fetchCSVData:[filesToBeFetched objectAtIndex:i]];
}
}
dispatch_async( dispatch_get_main_queue(), ^{
NSLog(#"Fetching is done *********************");
});
});
To answer the first part of the question:
All enumerate...UsingBlock methods don't work asynchronously.
Regarding the added part:
Assuming fetchCSVData works also synchronously, that's the preferred way to process the data
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
#autoreleasepool {
for (int i = 0; i < filesToBeFetched.count; i++) {
[applicationDelegate fetchCSVData:[filesToBeFetched objectAtIndex:i]];
dispatch_async( dispatch_get_main_queue(), ^{
NSLog(#"Fetching is done *********************");
});
}
}
});
i am working on threading....i came across this:
-(void)didRecieveResponse:(NSArray*)responseDic{
//Update DB status to '2', which means everything needs to b deleted
[[MediaService sharedInstance] updateMedia:2];
self.projectArray = responseDic;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int j = 0; j<[self.projectArray count]; j++) {
ProjectJsonModel *pModel = [self.projectArray objectAtIndex:j];
[self parseArray:pModel.imageArray project:pModel ptype:1];
[self parseArray:pModel.pdfArray project:pModel ptype:2];
[self parseArray:pModel.videoArray project:pModel ptype:3];
Media *tmpMedia = [[Media alloc] init];
tmpMedia.projectId = pModel.projetId;
tmpMedia.projectName = pModel.projectName;
// NSLog(#"DB project naem = %#",pModel.projectName);
tmpMedia.fileType = 4;
tmpMedia.fileLink = NULL;
tmpMedia.fileName = NULL;
//NSURL *fileUrl = [NSURL URLWithString:tmpMedia.fileLink];
//tmpMedia.fileName = [fileUrl lastPathComponent];
tmpMedia.status = 4;
[[MediaService sharedInstance] insertMedia:tmpMedia];
[tmpMedia release];
}
[self checkDbForDownload];
dispatch_async(dispatch_get_main_queue(), ^(void) {
//Stop your activity indicator or anything else with the GUI
//Code here is run on the main thread
});
});
which stores all online data into database.and it will displays in app. When it is checking for update application stops working.
In that break point is not entering in this loop, why?
The code in dispatch_async would run asynchronously. Debugging this from outer block of code would step out of the entire dispatch_async as a single line and will not step into the code block within. Put an additional break point in for (int j = 0; j<[self.projectArray count]; j++) { instead of stepping in from outer block to debug the code. This would stop the asyc background thread to stop when executing.