Nsthread, Nsrunloop, and Dispatch Queue

Source: Internet
Author: User

 In iOS multithreaded programming, nsoperation and Nsoperationqueue are undoubtedly the most common, and they can accommodate most of the threading operations. But when we do some special tasks, we still use Nsthread and Nsrunloop.

Nsthread well understood, it is equivalent to the thread class in Java.

Nsrunloop but not very well understood. Literally, runloop can be translated into " run Loops" or "Run loops ", and we can think of it as a special looping structure--we know that for or while loop statements, in fact Nsrunloop is a similar loop, but it's more than for/ While is much more complicated. I'm sure you've seen Apple's multithreaded Programming Guide, where "Run Loops" has a special introduction. But this document is too long and I'm sure it's hard for you to read it from beginning to end. This article demonstrates the use of Runnloop as an example, without overly complex content, to make sure you can read it-sometimes it's just that we're making things complicated.

First, the current Runloop

The current runloop refers to the runloop that is obtained with the Cfrunloopgetcurrent function, which is the runloop of the current thread and, in the absence of a child thread, may be the main thread of the application. If you use the Cfrunloopgetcurrent function directly in the main thread's method , the resulting runloop is the runloop of the main thread.

Create a new single View application. Drag a button and a textview into the viewcontroller.xib. And connect all two objects to the source code.

The action for implementing the button is as follows:

-(Ibaction) Runorstop: (ID) Sender {

if ([@ "Run" IsEqualToString:btRun.titleLabel.text]) {

Tvlist.text=nil;

[btrunsettitle:@ "Stop" forstate:uicontrolstatenormal];

cfrunlooptimerref timer;

cfrunlooptimercontext timer_context;

bzero (&timer_context, sizeof (Timer_context));

timer_context.info = self ;

timer = cfrunlooptimercreate (NULL, cfabsolutetimegetcurrent (), 2, 0, 0, _timer, &timer_context);

mrunloopref=cfrunloopgetcurrent ();

Cfrunloopaddtimer ( mrunloopref, timer, kcfrunloopcommonmodes);

Cfrunlooprun ();

}else{

[btrunsettitle:@ "Run" forstate:uicontrolstatenormal];

if ( mrunloopref )

cfrunloopstop ( mrunloopref );

 }

}

The button Btrun is a ping-pong button, and when the user clicks it, its title toggles between run and stop.

Runloop is an active loop that is driven by a variety of "input sources". Similarly, a for statement is driven by a loop variable, and when the loop variable reaches a value, the loop aborts. The input source of Runloop can have many types, here we only use the most common timer cfrunlooptimerref. When constructing a timer, a cfrunlooptimercontext is required as the context for initialization.

This context is a struct (with 5 members), where the info member is the void* type (that is, the ID type), and for us it is possible to pass some useful objects, such as Self--self, which is quite useful because self makes it easy for us to invoke the Member method in the C function:

Cfrunlooptimercontext Timer_context;

Bzero (&timer_context, sizeof (Timer_context));

timer_context.info = self ;

The other 4 members of the struct are meaningless to us. So the above 3 sentences can actually be written as:

Cfrunlooptimercontext timer_context={0, self , null, null, null};

The next step is to construct the timer using this context:

timer= cfrunlooptimercreate (NULL, cfabsolutetimegetcurrent (), 2, 0, 0, _timer, &timer_context);

Several parameters except null and 0 are: Timer start time, interval seconds, timed execution function, context pointer.

Other parameters We understand that we will discuss it later, except for the _timer--function. Next:

Mrunloopref=cfrunloopgetcurrent (); Gets the runloop of the current thread, and saves the Runloop in Mrunloopref. Mrunloopref needs to be declared as a static variable, which makes it easier for us to access the C function _timer:

Staticcfrunloopref mrunloopref;

This sentence adds a timer to the Runloop:

Cfrunloopaddtimer ( mrunloopref, timer, kcfrunloopcommonmodes);

This sentence starts Runloop:

Cfrunlooprun ();

Implement the _timer () function as follows:

void _timer (cfrunlooptimerref timer __unused, void *info)

{

loops++;

ID obj= (ID) info;

[obj performselectoronmainthread: @selector (Updatetextview) WithObject:nilwaitUntilDone:NO];

}

The _timer function, by convention, is a cfrunlooptimercallback structure, so it has two parameters:

Cfrunlooptimerref timer, void *info

The loops variable is also declared static (conveniently called in the C function), which makes no sense, and we only use it to record the number of loops.

The info parameter (which we actually specify as a self object) comes in handy here and we'll call the self's Updatetextview method here. Because the Updatetextview method updates the UI, the UI refresh should be done in the main thread according to Ukit, so we use the performselectoronmainthread to force the Updateview method to execute on the main thread.

The Updateview method is implemented as follows:

-(void) updatetextview{

tvlist.text=[nsstringstringwithformat:@ "%@\n%d", Tvlist.text,loops];

//Scroll to the bottom of TextView

nsrange range;

range = nsmakerange ([[Tvlisttext] length], 0);

[Tvlistscrollrangetovisible:range];

}

Run the program, when we click the Run button, the Runloop loop will be executed over and over, and the number of cycles of execution will be shown in TextView.

Wait, why is this?

When you click on the "Stop" button, you find that Runloop does not stop. Conversely, when you click the "Run" button again, Runloop seems to loop faster! Basically 1 seconds to execute. If you repeatedly click on the "Stop/run" button, the loop will get faster and quicker!

Cfrunloopstop does not seem to have been executed. In fact, Getcurrentrunloop get is the current thread of the Runloop, for the present situation, is actually the main thread of the Runloop. You have added a new source to the runloop of the main thread, but you do not have permission to stop it. And because you've clicked the Run button multiple times, Runloop has been added to multiple timer! This causes the _timer function to be executed more at the same time.

To stop Runloop, you need to create your own thread and then stop its runloop. This can also bring another benefit: Runloop does not block the main thread! By looking closely at the results of the program's operation, you will find that when the Run button is pressed, the state of the button is always in the highlight state and not restored to the normal state:

The Stop button background always renders highlight blue, because the main thread is blocked by Runloop. The button will not revert to the normal state unless Runloop is stopped.

Well, we only have to create a nsthread.

Runloop in sub-threads

Each thread has its own runloop, with the cfrunloopgetcurrent () function to get the runloop of the current thread. If there are no sources in Runloop, Runloop will not run. We can add a new source for this runloop.

Modify the Runorstop method code to:

-(Ibaction) Runorstop: (ID) Sender {

if ([@ "Run" IsEqualToString:btRun.titleLabel.text]) {

Tvlist.text=nil;

[btrunsettitle:@ "Stop" forstate:uicontrolstatenormal];

nsthread *thread = [[Nsthreadalloc] initwithtarget:selfselector: @selector (athread) Object:nil];

[Thread start];

}else{

[btrunsettitle:@ "Run" forstate:uicontrolstatenormal];

if ( mrunloopref )

cfrunloopstop ( mrunloopref );

 }

}

The Athread method is also implemented as follows:

-(void) athread{

cfrunlooptimerref timer;

Cfrunlooptimercontext timer_context={0, self , null, null, null};

timer = cfrunlooptimercreate (NULL, cfabsolutetimegetcurrent (), 2, 0, 0, _timer, &timer_context); /c10>

mrunloopref=cfrunloopgetcurrent ();

Cfrunloopaddtimer ( mrunloopref, timer, kcfrunloopcommonmodes);

Cfrunlooprun ();

}

As you can see, in the Runorstop method, we created a new Nsthread object and started it. The original Runloop code was moved to the new threading method Athread.

Run the program, you can use stop to stop it after you run the Runloop. At the same time, the main thread is no longer blocked, after the stop button point, after a short highlight state is restored to the normal state, the Stop button is no longer a strange blue.

Third, add custom source

We can also try to define a custom input source. This way, when the timer source is triggered, we can also invoke the custom source and do something else. To trigger another source, use the function cfrunloopsourcesignal:

Voidcfrunloopsourcesignal (cfrunloopsourceref source);

Add this sentence to the _timer function:

if (source) cfrunloopsourcesignal (source);

The parameter source specifies the input source to trigger.

We modify the Athread method as follows:

-(void) athread{

Cfrunloopsourcecontext Source_context;

bzero (&source_context, sizeof (Source_context));

source_context.perform = _perform;

Source = cfrunloopsourcecreate (NULL, 0,&source_context);

Cfrunloopaddsource (Cfrunloopgetcurrent (), source, kcfrunloopcommonmodes);

...

}

Where source is declared as a static variable:

Staticcfrunloopsourceref Source;

Then implement the _perform function:

void _perform (void *info)

{

if (loops%10==0) {

cfrunloopstop (mrunloopref);

printf ("Loops=%d,runloop is stopped.\n", loops);

 }

}

Finally, modify the Runorstop method, commenting the following statement, because Runloop's stop we gave the _perform function to do:
[Btrun settitle:@ "Stop" forstate:uicontrolstatenormal];

......

[Btrun settitle:@ "Run" forstate:uicontrolstatenormal];

if (mrunloopref)

Cfrunloopstop (MRUNLOOPREF);

Now executing the program, the Runloop will automatically stop every time it runs 10 times:

Loops=10,run Loop isstopped.

Loops=20,run Loop isstopped.

Loops=30,run Loop isstopped.

Sample code Download: http://download.csdn.net/detail/kmyhy/4426395

Iv. Dispatch Source

In the iOS asynchronous programming model, threading is the most traditional solution. However, the threading model still has some drawbacks: it is difficult to write and the scalability is not strong. iOS supports parallel programming with Dispathqueue and Dispatch source (refer to the Apple Document "Concurrency Programming Guide"). The above code can also be solved by parallel parallel programming.

Modify Runoorstop: The code is:

-(Ibaction) Runorstop: (ID) Sender {

Source = dispatch_source_create (dispatch_source_type_data_add, 0, 0,dispatch_get_global_queue (dispatch _queue_priority_default, 0));

Dispatch_source_set_event_handler (source, ^{

if (loops%10==0) {

dispatch_source_cancel (source);

dispatch_release (source);

Dispatch_source_cancel (timer);

dispatch_release (timer);

printf ("Loops=%d,dispatchsource is stopped.\n", loops);

 }

 });

Dispatch_resume (source);

Timer = dispatch_source_create (dispatch_source_type_timer, 0, 0,dispatch_get_global_queue (DISPATCH_ Queue_priority_default, 0));

Dispatch_source_set_timer (Timer, dispatch_time_now, 1ull * nsec_per_sec, 0);

Dispatch_source_set_event_handler (timer, ^{

loops++;

[Selfperformselectoronmainthread: @selector (Updatetextview) WithObject:nilwaitUntilDone:NO];

dispatch_source_merge_data (source, 1);

 });

Dispatch_resume (timer);

}

where timer and source are declared as external static variables:

staticdispatch_source_t Source,timer;

Run the program. No threads are used, no runloop, but the same effect is still achieved. As you can see, dispatch queue parallel programming has many advantages: there is no need to explicitly create line rountines accesses to allocate stack space for threads, code to simplify, block syntax support.

Nsthread, Nsrunloop, and Dispatch Queue

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.