Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

gnasher729

Suspended
Nov 25, 2005
17,980
5,565
So, you are asserting that I, the coder, don't ever (across the entire computer industry) explicitly call for an asynchronous I/O ... big assertion. You are saying that I, the coder, can only explicitly call for synchronous I/O on a background thread.

Even if you are right, the code on the front thread continues to run while the background thread blocks on its synchronous I/O. Whether I, the app coder, explicitly put a synchronous I/O on a background thread or the system does it, etc. is an implementation issue.

Performing any operations in a background thread in MacOS X or iOS is so easy, it is quite trivial to perform asynchronous I/O by making a synchronous call on a background thread.

But with asynchronous I/O, the I/O itself is not the only problem. There is data to be read/written. There are actions to be taken when the data is read, or actions not to be taken until the data is written. With asynchronous I/O, you'll have to figure out when to do this. By using synchronous I/O on a background thread, doing this is trivial.
 

multinode

macrumors regular
Feb 4, 2011
150
0
A synchronous design is one where return implies completion. An asynchronous design is one where return does not imply completion, that is, "return" is separate from "complete".

An example of a synchronous design is the classis Standard I/O <stdio.h>. All its functions are designed so that a return to the caller implies that the operation embodied by the function are complete, for whatever definition of "complete" is appropriate to the function and the stream. "Complete" doesn't necessarily mean "flushed to disk", because stdio is explicitly designed for in-process buffering.

Because an asynchronous design separates "return" and "complete", they must have a separate mechanism for indicating completion. There are different ways of doing this, such as the real-world examples described here:
http://en.wikipedia.org/wiki/Asynchronous_I/O

Since an asynchrnous design is one that separates "return" and "complete", for any practical purpose, a synchronous design is a design where return is the mechanism that indicates completion.

An asynchronous design without a mechanism for discovering or indicating completion would be extremely difficult to use. So much so that I suspect there are no such designs. However, I could be wrong, so if you know of one, or can explain how such a design would work, please describe it. That is, it would provide the same API and semantics as a synchronous design, e.g. stdio, but would actually be fully asynchronous.

Whether the completion mechanism for async is a callback, a completion routine, a signal, etc., there is always a mechanism other than return. So one could reasonably infer that if a design has no separate mechanism for discovering or indicating completion, then that design isn't asynchronous. In other words, the lack of separation between return and completion is exactly what makes a design synchronous.

Yes to all of the above. One item you failed to mention: asynchronous I/O allows subsequent operations to execute before the I/O completes.

I think you're doing a bit of circular reasoning, i.e. you assume that operations following the I/O call do not execute until the I/O gives us its completion value and then proceed to assert that the I/O is therefore synchronous according to how you know synchronous I/O to work.

Your following statements deal strictly with how Apple implements the writeToFile:atomically: method. I have no knowledge of what they do "under the covers" ... do you?

Now refer to the writeToFile:atomically: method. What does its design tell you? First, it takes two arguments. Neither of these is a completion routine, callback, or any other type of completion handler or indicator. (Could be something they do "under the covers".) Second, it returns one value, a boolean with two valid states: YES and NO. The meaning of these states indicates the success or failure of the embodied operation.

True, but there is nothing we know from the semantics of the method that tells us that the following code waits for that completion. If it waits, then the I/O is synchronous ... if it proceeds without waiting then the I/O is asynchronous.

There is no other state that could indicate "incomplete", nor is it possible to determine a valid YES or NO unless the operations are complete, so the return value is clearly intended as a synchronous design, where return implies completion.

True about an "incomplete indication", but sorry, your conclusion doesn't follow from that.

There is no other logical alternative for this method, given the design of C, Objective-C, and the binary calling conventions used.

You are assuming things that are not obvious to me from the method semantics ... perhaps you know what C and binary codes Apple implements "under the covers".

In particular, there is no way that the returned YES or NO value can be changed after the method returns. Neither C nor Objective-C works that way.

Agreed.

It's impossible for code that would execute after the return to execute while the method is completing asynchronously.

Not true! That behavior is precisely what asynchronous I/O allows!

Once again, you are assuming that the following code waits for the I/O to complete. How do you know that to be true?

If there's some way to implement this writeToFile:atomically: method that allows it to return YES or NO, and then later revoke that returned value, then please explain exactly how that would work, using actual code rather than pseudo-code. I assert that it's impossible to do this using C or Objective-C. In fact, I think it would take an extraordinary language to express this "return then revoke" capability.

I've never said nor did I mean to imply a two step (YES/NO and a later revision of that completion result).

Also see the O_NONBLOCK option to open(2). There are also non-blocking semantics available for read(2), write(2), etc. And see fcntl(2), and the SIGIO and SIGURG signals.

Furthermore, OS X supports the aio_* family of functions. See 'man aio'.

Interesting ... thank you. But this doesn't imply anything about the writeToFile:atomically method. Still could be either way ... ambiguous from the method semantics alone.
 
Last edited:

multinode

macrumors regular
Feb 4, 2011
150
0
Performing any operations in a background thread in MacOS X or iOS is so easy, it is quite trivial to perform asynchronous I/O by making a synchronous call on a background thread.

But with asynchronous I/O, the I/O itself is not the only problem. There is data to be read/written. There are actions to be taken when the data is read, or actions not to be taken until the data is written. With asynchronous I/O, you'll have to figure out when to do this. By using synchronous I/O on a background thread, doing this is trivial.

Again, there is nothing in the semantics of the writeToFile:atomically that tell me when the completion value is given to me ... before or after the following code executes. You are assuming the former.
 

chown33

Moderator
Staff member
Aug 9, 2009
10,731
8,407
A sea of green
[One item you failed to mention: asynchronous I/O allows subsequent operations to execute before the I/O completes. I think you're doing a bit of circular reasoning, i.e. you assume that operations following the I/O call do not execute until the I/O gives us its return (complete) value and then proceed to assert that the I/O is therefore synchronous according to how you know synchronous I/O to work ... QED.

I made no assumptions that subsequent I/O operations must wait before starting another one. That's your inference.

Please clariofy your terminology. The red-hilited parts ambiguous. The "operations" could referring only to I/O operations, or "operations" could mean execution of user-written code after the return, such as comparisons of the return value in an if statement, or assignment of the return value to a variable. The async I/O system can accept subsequent I/O operations, but that means that user code runs and requests those I/O operations. That user code consists of "operations" (CPU instructions) that are not I/O operations. So I'm unclear on exactly what you're criticizing.

The instructions (operations) after the async function returns are outside the control of the I/O system. Any value returned by an async function belongs to the instructions that execute after the return.

Your following statements deal strictly with how Apple implements the writeToFile:atomically: method. I have no knowledge of what they do "under the covers" ... do you?
I asser that the design of that method is inherently synchronous. There is no way for it to tell the code that executes after a return about any async completion.

You keep implying that a design can be asynchronous even if there is no separate mechanism for indicatiing completion. I assert that such a thing is impossible. Please explain how an API exactly like the writeToFile:atomically: method could be implemented in an asynchronous manner, without adding a separate completion mechanism. This is not just a random challenge, it is the very heart of the disagreement.

True, but there is nothing we know from the semantics of the method that tells us that the following code waits for that completion. If it waits, then the I/O is synchronous ... if it proceeds without waiting then the I/O is asynchronous.
I assert that it can't maintain the contract described in the docs, and be asynchronous. There is no way for it to report completion.

The return value (a boolean) reports success or failure. That value cannot be determined until completion. Therefore, the method cannot return that value and also be asynchronous; I asser that it's a logical impossibility.

You clearly believe that it's possible for this method to be asynchronous, but you have yet to show how that's possible. It could be done by adding an async completion mechanism, but that's adding something that the method currently doesn't have.

So if you can show how this method could have asynchronous completion and still fulfill it's documented contract, I'd like to see it. Basically, you keep saying that the method could be asynchronous and we don't know, and I keep saying that there is a logical contradiction if the method is asynchronous and returns success/fail as a boolean.

Not true! That behavior is precisely what asynchronous I/O allows!
I'm not contesting that. I'm contesting that a method with this exact API can be asynchronous at all. I see no way it can be done. Please describe how it can be done.

Once again, you are assuming that the following code waits for the I/O to complete. How do you know that to be true?
No I'm not. I'm assuming that the following code gets a YES/NO boolean that indicates success. The only logical way that boolean can indicate success is if the I/O operations have completed.

If the method returns a success/fail boolean, then that logically precludes any asynchronous completion. Completion must be synchronous in order for the method to return a success/fail boolean.

It is logically impossible to have an incomplete I/O operation and a boolean that indicates success, because success cannot be determined until the I/O operations are actually completed.

Again, you seem to be asserting that the method CAN return an indicator of success while also being asynchronous (separate completion). Please explain exactly how that can be achieved. I'm not looking for how Apple implements it. I'm only looking for a logical explanation that resolves what I see as a logical contradiction.

I've never said nor did I mean to imply a two step (YES/NO and a later revision of that completion result).
That's exactly how I interpreted your earlier assertions about subsequent operations. See the above where I request clarification.


Again, there is nothing in the semantics of the writeToFile:atomically that tell me when the completion value is given to me ... before or after the following code executes.
Yes there is.

C guarantees that when a function returns, any value being returned belongs to the caller. If the returned type is a reference type (pointer), then the called function may keep a pointer, and some asynchronous code could possibly alter the pointed-at data. If the returned type is a simple type (int, float, double, etc.) then the called function can no longer alter the returned value. Since C only supports those two kinds of types (simple types and reference types), those two rules cover the entire C type space; C has no other types.

Objective-C methods are essentially a specific kind of C function. Read the Objective-C Runtime reference docs for how the message-send operation resolves a method-signature into a function pointer.

Since the method in question returns a simple type (boolean), there is no way the method can do anything except return the boolean completion value, thus completely giving up control to the caller. Since it must return a value that can only be determined after completion, the method must logically be synchronous. That is, it must wait for completion so it has a value it can return.

Since you seem to think otherwise, please explain how the method would be able to return a valid success/fail boolean without having waited for completion. Again, this is the heart of the disagreement, which you have not yet explained.
 

multinode

macrumors regular
Feb 4, 2011
150
0
I made no assumptions that subsequent I/O operations must wait before starting another one. That's your inference.

Please clariofy your terminology. The red-hilited parts ambiguous. The "operations" could referring only to I/O operations, or "operations" could mean execution of user-written code after the return, such as comparisons of the return value in an if statement, or assignment of the return value to a variable. The async I/O system can accept subsequent I/O operations, but that means that user code runs and requests those I/O operations. That user code consists of "operations" (CPU instructions) that are not I/O operations. So I'm unclear on exactly what you're criticizing.

The instructions (operations) after the async function returns are outside the control of the I/O system. Any value returned by an async function belongs to the instructions that execute after the return.


I asser that the design of that method is inherently synchronous. There is no way for it to tell the code that executes after a return about any async completion.

You keep implying that a design can be asynchronous even if there is no separate mechanism for indicatiing completion. I assert that such a thing is impossible. Please explain how an API exactly like the writeToFile:atomically: method could be implemented in an asynchronous manner, without adding a separate completion mechanism. This is not just a random challenge, it is the very heart of the disagreement.


I assert that it can't maintain the contract described in the docs, and be asynchronous. There is no way for it to report completion.

The return value (a boolean) reports success or failure. That value cannot be determined until completion. Therefore, the method cannot return that value and also be asynchronous; I asser that it's a logical impossibility.

You clearly believe that it's possible for this method to be asynchronous, but you have yet to show how that's possible. It could be done by adding an async completion mechanism, but that's adding something that the method currently doesn't have.

So if you can show how this method could have asynchronous completion and still fulfill it's documented contract, I'd like to see it. Basically, you keep saying that the method could be asynchronous and we don't know, and I keep saying that there is a logical contradiction if the method is asynchronous and returns success/fail as a boolean.


I'm not contesting that. I'm contesting that a method with this exact API can be asynchronous at all. I see no way it can be done. Please describe how it can be done.


No I'm not. I'm assuming that the following code gets a YES/NO boolean that indicates success. The only logical way that boolean can indicate success is if the I/O operations have completed.

If the method returns a success/fail boolean, then that logically precludes any asynchronous completion. Completion must be synchronous in order for the method to return a success/fail boolean.

It is logically impossible to have an incomplete I/O operation and a boolean that indicates success, because success cannot be determined until the I/O operations are actually completed.

Again, you seem to be asserting that the method CAN return an indicator of success while also being asynchronous (separate completion). Please explain exactly how that can be achieved. I'm not looking for how Apple implements it. I'm only looking for a logical explanation that resolves what I see as a logical contradiction.


That's exactly how I interpreted your earlier assertions about subsequent operations. See the above where I request clarification.



Yes there is.

C guarantees that when a function returns, any value being returned belongs to the caller. If the returned type is a reference type (pointer), then the called function may keep a pointer, and some asynchronous code could possibly alter the pointed-at data. If the returned type is a simple type (int, float, double, etc.) then the called function can no longer alter the returned value. Since C only supports those two kinds of types (simple types and reference types), those two rules cover the entire C type space; C has no other types.

Objective-C methods are essentially a specific kind of C function. Read the Objective-C Runtime reference docs for how the message-send operation resolves a method-signature into a function pointer.

Since the method in question returns a simple type (boolean), there is no way the method can do anything except return the boolean completion value, thus completely giving up control to the caller. Since it must return a value that can only be determined after completion, the method must logically be synchronous. That is, it must wait for completion so it has a value it can return.

Since you seem to think otherwise, please explain how the method would be able to return a valid success/fail boolean without having waited for completion. Again, this is the heart of the disagreement, which you have not yet explained.

I understand your points exactly and btw, I'm sorry for the ambiguity re "operations" ... I meant following user written code ... not necessarily additional I/O calls.

I'm going to do some actual testing ... more tomorrow. What time zone are you in? I'm in San Jose, CA.
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
This is actually blowing my mind. This method clearly works in a synchronous manner. If, internally, some asynchronous I/O happens, but the method wraps that and returns on completion... So what?! The method is presenting a synchronous interface. It could start new processes, new threads, whatever. When it returns it damn well better be done, because the contract says so! Writes to a file... returns YES if operation is successful. OK. If the method is still writing in another thread when it returns, there's no way to know if the operation was successful. And there's no use in this method doing async I/O. We can't do anything else on the calling thread. We're waiting for the write to finish anyway!

I guess I'm just confused about what we're arguing about. If the method does and returns the way its documentation says, the implemention is irrelevant. Spin 40 threads, but you better damn well be done (terminal success or failure) when you return because you SAID SO.

Sorry this isn't super-well supported with generated object code or something, but this seems like a specifically logical argument, not one that requires implementation details to resolve.

-Lee
 

chown33

Moderator
Staff member
Aug 9, 2009
10,731
8,407
A sea of green
I understand your points exactly and btw, I'm sorry for the ambiguity re "operations" ... I meant following user written code ... not necessarily additional I/O calls.

I'm going to do some actual testing ... more tomorrow. What time zone are you in? I'm in San Jose, CA.

I predict that the results will indicate synchronous behavior, for both values of atomically:.

It doesn't matter what time zone I'm in. Post your results, and eventually I'll see them.

Also, regardless of the results or even a lack of results, please provide this explanation:
Since you seem to think otherwise, please explain how the method would be able to return a valid success/fail boolean without having waited for completion. Again, this is the heart of the disagreement, which you have not yet explained.
Pseudo-code will suffice. The only way I can see to maintain the contract is to wait for writing and renaming to complete, which means it can't be async. As lee1210 noted, this is a logical issue, not one of implementation details, so it's orthoganal to the question of getting test results.
 

multinode

macrumors regular
Feb 4, 2011
150
0
And the winner is ... drummmmmmm rolllllllll ... CHOWN33

I was so unwilling to accept that Apple (seemingly) would not allow asynchronous I/O, that I overlooked a key item ... the method in question did return a result to the caller and that returned result does indeed happen before any following code. Furthermore, there was never any question in my mind that the returned result signified completion. I could say more, but case closed.

FWIW, I was thinking of the method as a procedure, not a function ... ala Pascal ... the old, old Apple language. So, maybe (???) if the return value had been a void, then asynchronousity might have been on the table. Comment anyone?

In all of this discussion, somebody alluded to the ATOMICALLY parameter as being the determining factor in deciding that the method was synchronous. I don't agree. An atomic operation is merely indivisible.

I ran some test code last night and, of course, all of the above was validated. Thanx guys.
 

chown33

Moderator
Staff member
Aug 9, 2009
10,731
8,407
A sea of green
And the winner is ... drummmmmmm rolllllllll ... CHOWN33

Glad you finally agreed.

I was so unwilling to accept that Apple (seemingly) would not allow asynchronous I/O, that I overlooked a key item ... the method in question did return a result to the caller and that returned result does indeed happen before any following code.
As I described in post #11. Those places where I used the word "complete" were intentional.

Furthermore, there was never any question in my mind that the returned result signified completion. I could say more, but case closed.
The sentence in red seems inconsistent with your post #15:
Asynchronousity doesn't mean immediate COMPLETION ... it means allowing following code to execute PRIOR to the asynchronous code's completion. I guess I might say immediate RETURN (maybe) but not immediate COMPLETION.
The way I read the underlined sentence, you acknowledge the separation of return (hence the returned result) from completion. Which seems to contradict the sentence in red.


FWIW, I was thinking of the method as a procedure, not a function ... ala Pascal ... the old, old Apple language. So, maybe (???) if the return value had been a void, then asynchronousity might have been on the table. Comment anyone?
Strictly speaking, C only has functions, no procedures. In its early days, it didn't have a void type, so a function always had a return value, even if that value had no meaning (a garbage value). [1]

If the method was declared as returning void, then you still can't have asynchronicity unless you add something to the API. With no return value, you've eliminated any way to determine success/fail, and there's still no way to report completion.

You could add parameters that provide those mechanisms, but now it's a different method. There are other possible API additions; for examples, read the Wikipedia link I posted earlier about async I/O.

Without adding a mechanism to the method's API to report completion, it still can't be async. If it's unclear why, reread my earlier posts.

In all of this discussion, somebody alluded to the ATOMICALLY parameter as being the determining factor in deciding that the method was synchronous. I don't agree. An atomic operation is merely indivisible.
I reread the thread and found no such post or allusion. If you find it, point out exactly which post it is.


[1] http://en.wikipedia.org/wiki/C_(programming_language)#Characteristics
"In C, all executable code is contained within subroutines, which are called "functions" (although not in the strict sense of functional programming). "
Also see:
http://en.wikipedia.org/wiki/C_(programming_language)#K.26R_C
In particular, note the optional use of 'int' for declared function type (implicitly int).
 

multinode

macrumors regular
Feb 4, 2011
150
0
chown33 said:
Asynchronousity doesn't mean immediate COMPLETION ... it means allowing following code to execute PRIOR to the asynchronous code's completion. I guess I might say immediate RETURN (maybe) but not immediate COMPLETION.

The way I read the underlined sentence, you acknowledge the separation of return (hence the returned result) from completion. Which seems to contradict the sentence in red.

Actually, I was having trouble with notion of return which is why I hesitantly said "I guess I might say ..." By return I was thinking about releasing code flow control, not returning a value. So I was torturing the language a bit. :D
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.