I have been learning the internals of an operating system and I am confused as to what the basic difference between synchronous and asynchronous I/O is.
How does an operating system know whether it is synchronous or asynchronous?
Synchronous I/O mean that some flow of execution (such as a process or thread) is waiting for the operation to complete. Asynchronous I/O means that nothing is waiting for the operation to complete and the completion of the operation itself causes something to happen.
Synchronous I/O -- some execution vehicle (like a process or thread) that initiates the I/O also waits for the I/O to complete (and perhaps completes it). When the I/O completes, that same execution vehicle goes on to do something else, perhaps using the results of the I/O.
Example:
int i = read (file_handle, buffer, length);
if (i <= 0)
return;
// handle results
Here, the read operation starts a read from the file. The same thread that calls read gets the return value when the read operation completes and can process the result.
Asynchronous I/O -- no execution vehicle waits for the I/O to complete. When the I/O completes, whatever execution vehicle happens to complete the I/O may arrange for later things to happen.
Example:
async_read (file_handle, buffer, length, completion_handler);
// do other stuff having nothing to do with the read
...
completion_handler(int count)
{
if (count < 0)
return;
// handle results
}
Here, the call to async_read starts the read operation. The thread that started the operation can go on to do other things entirely. When the operation completes, the implementation calls completion_handler (possibly by another thread) which gets the results of the operation.
Generally the operating system doesn't have to know which is which. You can, for example, implement only asynchronous operations and have the completion handler unblock the synchronous thread. Usually, deep under the hood, they all look the same with some piece of code called when the operation completes that does whatever has to be done.
You can easily turn either into the other.
If you have only asynchronous operations and want a synchronous operation, just call the asynchronous operation and then block on something that is unblocked by the completion handler.
If you have only synchronous operations and want an asynchronous operation, just create a new thread to call the synchronous operation and have it invoke the completion handler when the synchronous operation returns.
Related
I would like to clear up what it means to be a asynchronous/synchronous and blocking/non-blocking operations in Scala Play using Scala's Future.
So we can have:
Asynchronous and non-blocking
Asynchronous and blocking
Synchronous and non-blocking
Synchronous and blocking
In the Play documentation it says that all operations are asynchronous. But I would like to know how the following would be classed:
If I call an external web service and I have to wait for the response then is this considered to be a asynchronous and blocking operation? For example:
def externalWebCall(url : String): Future[SomeData]
def storeData(data : String) : Future[Unit]
for {
data <- externalWebCall(url)
_ <- storeData(data)
} yield(data)
In this example, I don't want storeData to execute until the externalWebCall service has completed. Is the above code the right way to achieve this? If so I think this is asynchronous and blocking.
The initial request that comes to Play service is treated in an asynchronous and non-blocking way according to the documentation. My understanding of this is that when the Play server receives the request it will not block the main thread. It will then service the request and then make a call to the callback of this request and then return the result. Is that correct?
When people use the term "asynchronous", they usually mean "non-blocking", in the sense that the current execution thread will not stop and wait for the result. In general, synchronous means blocking, asynchronous means non-blocking.
It seems you are confusing "blocking" with "ordering the execution". Your example with the Futures is completely asynchronous, and it equivalent to
val result: Future[Unit] = externalWebCall(url).flatMap(storeData)
storeData can only execute when externalWebCall is done, but any code that would come after val result = ... could also execute before either externalWebCall or storeData. The execution of these methods is wrapped in a Future and run in a different thread, so you have no way of knowing when it will happen. That is what asynchronous means.
The terms blocking and asynchronous have different meanings, but are often confused or used interchangeably.
blocking means that the current thread waits for another thread to do something before executing further instructions. The current thread is blocked until the other thread completes and then it can continue.
asynchronous means that an operation happens on another thread while the current thread continues to execute. The current thread initiates an operation but then continues to execute. When the asynchronous operation completes it notifies the current thread by raising an event or calling some event handler function.
Blocking functions look like normal functions and there is not necessarily any indication that the code being called is blocking or non blocking. So a println statement may be blocking for stderr but non-blocking for stdout.
Asynchronous functions will always have a mechanism for being notified of completion of the operation and this will be visible in the interface. In Scala this usually means returning Future[T] rather than T.
In your example, both externalWebCall and storeData are asynchronous because each method returns Future.
storeData takes a data argument that is only available when externalWebCall completes, so these two operations must by definition operate sequentially.
I am using the following code in a loop:
-(void)getUpdatedComments
{
if(checkComments)
{
objParseOperation=[[ParseOperation alloc] initWithUDID:[[NSUserDefaults standardUserDefaults] valueForKey:kDeviceUDID]:self];
[operationQueue addOperation:objParseOperation3];
}
}
where operationQueue is an object of type NSOperationQueue. I am calling this method every few seconds.
If I call this method after the first time, do I need to cancel the previous operation or just do [objParseOperation release]?
If you are going to use the same queue for adding more new operations then there isn't much use in releasing it and creating a new one. Simply canceling all operations and then adding more operations is enough. You can do so by calling cancelAllOperations on the queue. Note that operations that are already running will continue to run unless they check for the cancellation.
This method sends a cancel message to all operations currently in the queue. Queued operations are cancelled before they begin executing. If an operation is already executing, it is up to that operation to recognize the cancellation and stop what it is doing.
Wether or not releasing the queue will immediately release the enqueued operations or not is not documented and hence should be considered as undefined behavior. Therefor you shouldn't assume that it will work either way and you should not rely on it (see dangerous to autorelease NSOperationQueue).
There are however evidence that suggests that operations will retain their queue such as that GCD queues are retained by the system while they have asynchronous blocks running/pending. You can read in the Grand Central Dispatch documentation that "the queue is retaind by the system until the block has run to completion". Still, the documentation doesn't specify the behavior for NSOperationQueues like mentioned above.
dispatch_async
Submits a block for asynchronous execution on a dispatch queue and returns immediately.
void dispatch_async(
dispatch_queue_t queue,
dispatch_block_t block);
Parameters
queue
The queue on which to submit the block. The queue is retained by the system until the block has run to completion. This parameter cannot be NULL.
block
The block to submit to the target dispatch queue. This function performs Block_copy and Block_release on behalf of callers. This parameter cannot be NULL.
Discussion
This function is the fundamental mechanism for submitting blocks to a dispatch queue. Calls to this function always return immediately after the block has been submitted and never wait for the block to be invoked. The target queue determines whether the block is invoked serially or concurrently with respect to other blocks submitted to that same queue. Independent serial queues are processed concurrently with respect to each other.
This question already has answers here:
Difference between DispatchQueue.main.async and DispatchQueue.main.sync
(4 answers)
Closed 3 years ago.
I'm reading the docs on dispatch queues for GCD, and in it they say that the queues are FIFO, so I am woundering what effect this has on async / sync dispatches?
from my understand async executes things in the order that it gets things while sync executes things serial..
but when you write your GCD code you decide the order in which things happen.. so as long as your know whats going on in your code you should know the order in which things execute..
my questions are, wheres the benefit of async here? am I missing something in my understanding of these two things.
The first answer isn't quite complete, unfortunately. Yes, sync will block and async will not, however there are additional semantics to take into account. Calling dispatch_sync() will also cause your code to wait until each and every pending item on that queue has finished executing, also making it a synchronization point for said work. dispatch_async() will simply submit the work to the queue and return immediately, after which it will be executed "at some point" and you need to track completion of that work in some other way (usually by nesting one dispatch_async inside another dispatch_async - see the man page for example).
sync means the function WILL BLOCK the current thread until it has completed, async means it will be handled in the background and the function WILL NOT BLOCK the current thread.
If you want serial execution of blocks check out the creation of a serial dispatch queue
From the man page:
FUNDAMENTALS
Conceptually, dispatch_sync() is a convenient wrapper around dispatch_async() with the addition of a semaphore to wait for completion of the block, and a wrapper around the block to signal its completion.
See dispatch_semaphore_create(3) for more information about dispatch semaphores. The actual implementation of the dispatch_sync() function may be optimized and differ from the above description.
Tasks can be performed synchronously or asynchronously.
Synchronous function returns the control on the current queue only after task is finished. It blocks the queue and waits until the task is finished.
Asynchronous function returns control on the current queue right after task has been sent to be performed on the different queue. It doesn't wait until the task is finished. It doesn't block the queue.
Only in Asynchronous we can add delay -> asyncAfter(deadline: 10..
I read that GCD synchronous queues (dispatch_sync) should be used to implement critical sections of code. An example would be a block that subtracts transaction amount from account balance. The interesting part of sync calls is a question, how does that affect the work of other blocks on multiple threads?
Lets imagine the situation where there are 3 threads that use and execute both system and user defined blocks from main and custom queues in asynchronous mode. Those block are all executed in parallel in some order. Now, if a block is put on a custom queue with sync mode, does that mean that all other blocks (including on other threads) are suspended until the successful execution of the block? Or does that mean that only some lock will be put on that block while other will still execute. However, if other blocks use the same data as the sync block then it's inevitable that other blocks will wait until that lock will be released.
IMHO it doesn't matter, is it one or multiple cores, sync mode should freeze the whole app work. However, these are just my thoughts so please comment on that and share your insights :)
Synchronous dispatch suspends the execution of your code until the dispatched block has finished. Asynchronous dispatch returns immediately, the block is executed asynchronously with regard to the calling code:
dispatch_sync(somewhere, ^{ something });
// Reached later, when the block is finished.
dispatch_async(somewhere, ^{ something });
// Reached immediately. The block might be waiting
// to be executed, executing or already finished.
And there are two kinds of dispatch queues, serial and concurrent. The serial ones dispatch the blocks strictly one by one in the order they are being added. When one finishes, another one starts. There is only one thread needed for this kind of execution. The concurrent queues dispatch the blocks concurrently, in parallel. There are more threads being used there.
You can mix and match sync/async dispatch and serial/concurrent queues as you see fit. If you want to use GCD to guard access to a critical section, use a single serial queue and dispatch all operations on the shared data on this queue (synchronously or asynchronously, does not matter). That way there will always be just one block operating with the shared data:
- (void) addFoo: (id) foo {
dispatch_sync(guardingQueue, ^{ [sharedFooArray addObject:foo]; });
}
- (void) removeFoo: (id) foo {
dispatch_sync(guardingQueue, ^{ [sharedFooArray removeObject:foo]; });
}
Now if guardingQueue is a serial queue, the add/remove operations can never clash even if the addFoo: and removeFoo: methods are called concurrently from different threads.
No it doesn't.
The synchronised part is that the block is put on a queue but control does not pass back to the calling function until the block returns.
Many uses of GCD are asynchronous; you put a block on a queue and rather than waiting for the block to complete it's work control is passed back to the calling function.
This has no effect on other queues.
If you need to serialize the access to a certain resource then there are at least two
mechanisms that are accessible to you. If you have an account object (that is unique
for a given account number), then you can do something like:
#synchronize(accountObject) { ... }
If you don't have an object but are using a C structure for which there is only one
such structure for a given account number then you can do the following:
// Should be added to the account structure.
// 1 => at most 1 object can access accountLock at a time.
dispatch_semaphore_t accountLock = dispatch_semaphore_create(1);
// In your block you do the following:
block = ^(void) {
dispatch_semaphore_wait(accountLock,DISPATCH_TIME_FOREVER);
// Do something
dispatch_semaphore_signal(accountLock);
};
// -- Edited: semaphore was leaking.
// At the appropriate time release the lock
// If the semaphore was created in the init then
// the semaphore should be released in the release method.
dispatch_release(accountLock);
With this, regardless of the level of concurrency of your queues, you are guaranteed that only one thread will access an account at any given time.
There are many more types of synchronization objects but these two are easy to use and
quite flexible.
When using a synchronous I/O such as fread which is buffered, the read operations are
postponed and combined, I think that isn't done synchronously.
So what's the difference between a buffered synchronous I/O and an asynchronous I/O?
My understanding of async I/O is that you're notified when it's done via an interrupt of some sort so you can do more I/O at that point. With buffered I/O, you do it and forget about it, you never hear about that particular I/O again.
At least that's how it is with the huge intelligent disk arrays we deal with.
The idea of async I/O is that you begin the I/O and return to doing other stuff. Then, when the I/O is finished, you're notified and can do more I/O - in other words, you're not waiting around for it to finish.
Specifically for the synchronous read case: you request some input and then wait around while it's read from the device. Buffering there just involves reading more than you need so it's available on the next read without going out to the device to get it.
Async reads, you simply start the process to read then you go off and do something else while it's happening. Whether by polling or an interrupt, you later discover that the read is finished and the data is available for you to use.
For writes, I'm not sure I can see the advantage of one over the other. Buffered sync writes will return almost immediately unless the buffer is full (that's the only time when an async write may have an advantage).
Synchronous I/O works on a polling basis: you poll, data is returned (when available---if not available, then: for blocking I/O, your program blocks until data is available; for non-blocking I/O, a status code is returned saying no data is available, and you get to retry).
Asynchronous I/O works on a callback basis: you pass in a callback function, and it gets called (from a different thread) when data becomes available.
From a programming point of view, synchronous IO would be handled in the same function/process eg.
var data0 = synchronousRead();
var data1 = synchronousRead();
whereas asynchronous IO would be handled by a callback.
asynchronousRead(callBack1);
doOtherStuff();
...
function callBack1(data)
{
data0 = data;
}
Synchronous IO is the "normal" kind where you call a routine, and flow of control continues when the routine has read into your local variable (ignoring writes).
Asynchronous IO involves setting up a buffer variable (static, global, or otherwise long lived / wide scope) and telling the system that you want data put into it when it eventually becomes available. Your program then continues. When the system has the data, it sends you a signal / event / message of some kind, telling you that you now have data in your buffer variable.
Async IO is usually used by GUI programs to avoid stalling the user interface while IO completes.
Look here. Evrything you want to know is explained.
link to wikipedia