PDA

View Full Version : Waiting for Method to finish.




larswik
Aug 26, 2013, 11:18 PM
I ran into a problem tonight. Basically I have 3 classes which 2 are viewControllers and one NSObject. My NSObject Class is called "BoilerPlateCode", it contains methods that I call often from different classes like accessing the Documents folder.

The problem that I have is viewController1 is pushing viewController2 on to the stack before it finishes saving. In viewController1's method viewWillDisappear: I have it call the BoilerPlateCode class to save the data to the Documents folder.

When viewController2 instantiates the viewDidLoad method is called. It then retrieves some of the saved data using the BoilerPlateCode to display on the screen.

The problem that I am having is that viewController2 is being pushed on the stack before VC1 has finished writing the data. The result is that the old data is loaded instead.

I tested this with 2 NSLogs, one writing out to the screen "Saved" from VC1 and the other writing out "Loaded" from VC2.

VC1

-(void)viewWillDisappear:(BOOL)animated{
if (shouldSaveTextView || ![currentXP isEqualToString:savedXP]) {
NSString *textFromView = notesField.text;
[characterLoadInfo setValue:textFromView forKey:@"textView"];
[characterLoadInfo setValue:currentXP forKey:@"savedXP"];
BoilerPlateCode *bpc = [[BoilerPlateCode alloc] init];
[bpc saveAllCharacter:characterName with:characterLoadInfo];
NSLog(@"saved");
}
}


VC2

- (void)viewDidLoad{
BoilerPlateCode *bpc = [[BoilerPlateCode alloc] init];
NSDictionary *charDict2 = [bpc reloadCharacter:characterName];
maxHP = [[charDict2 objectForKey:@"hitPoints"]intValue];
NSString *hp = nil;

if ([charDict2 objectForKey:@"currentHP"]) {
hp = [charDict2 objectForKey:@"currentHP"]; // If HP hs been modified use this
}
else if ([charDict2 objectForKey:@"hitPoints"]){ // If no combat has happened yet then use this
hp = [charDict2 objectForKey:@"hitPoints"];
}
else
hp = @"0";
NSLog(@"loaded");

}



2013-08-26 20:44:12.721 XP Tracker[7691:15503] loaded
2013-08-26 20:44:12.729 XP Tracker[7691:15503] saved


On the console I should see 'saved' first then 'loaded', but it is the opposite. So I am thinking that when I call the BoilerPlateCode object to perform the save task, it is performing this task as an asynchronous operation. This allows VC1 to push VC2 on the stack and start to load the data before it finishes saving it.

If this is the case is there a way to make it perform the save on the main thread so it has to wait till the save is finished before pushing VC2 on the stack and calling the load information?



gnasher729
Aug 27, 2013, 03:46 AM
On the console I should see 'saved' first then 'loaded', but it is the opposite. So I am thinking that when I call the BoilerPlateCode object to perform the save task, it is performing this task as an asynchronous operation. This allows VC1 to push VC2 on the stack and start to load the data before it finishes saving it.

If this is the case is there a way to make it perform the save on the main thread so it has to wait till the save is finished before pushing VC2 on the stack and calling the load information?

Before you go deep into multithreading code, I'd add two more NSLog to check which method is actually _called_ earlier. I suspect that the second view is created, and after that the first view is removed.

larswik
Aug 27, 2013, 02:11 PM
Thanks gnasher729. I spent a late night and found a work around. Instead of calling the method to save the data in the viewWillDisapear method I moved that data to the button method that calls that instantiates the new VC and I have it save first.

This solved the problem but I am still curious if it is a multi threading problem of not? My gut tells me it is not since I don't use any GCD to handle my class on a separate thread. The main thread should wait till it is finished writing the plist and then push the new VC on the stack. Then reload data it needs from the plist on the new VC.

Thanks again.

multinode
Aug 30, 2013, 02:40 PM
Larswick ... I had a similar problem.

You didn't say how you went from View1 to View2 ... I assume you used a segue. Suggestion: don't execute "PerformSegue" until you've checked that your save has been completed ... pseudo code:


while (!saved); //a barrier sync
PerformSegue;

larswik
Aug 30, 2013, 03:46 PM
After what gnasher729 said I did some more testing, but i used a UIButton to push the new VC on the stack with this code


[self.navigationController pushViewController:newCombat animated:YES];


I thought I had solved the problem by adding the code to the UIButton method to save the plist data. But after doing some more testing I moved my VC2 code that loaded data from a plist file to the viewWillAppear method instead of the viewDidLoad method and this solved the problem. Now all the data is being written before parts of it are begin reloaded.

I thought the original problem was multi threading related, but appears not to be.

Thanks

multinode
Aug 30, 2013, 09:23 PM
Hello Larswik ...

I see where you moved the loading of saved data to "ViewWillAppear" and you believe that your data loading now takes place AFTER that data is saved ... problem solved. I don't agree ... I think you are winning by accident and that at some point in the future you will be bitten again.

I think that you must use EXPLICIT synchronization such as I suggested with the "while(!saved);" barrier.

larswik
Aug 31, 2013, 02:24 AM
I do see what you are saying using the while loop till it is competed. But from what I learned in programming class even Object C is 'kind of' a procedural language. What I mean by that is even though a method is called it drops down line by line executing the code till the method exits.

Since I don't dispatch writeToFile: method on a separate thread it should finish the task before proceeding to the next line of code. I was little confused about the order of method calls when you push a new viewController on the stack. There are at least 3 methods called on a new VC when instantiated.

initWithNibName:
viewDidLoad
viewWillAppear:


and when your old viewController calls the viewWillDisappear:

So I put an NSLog in each method without having any data written to the Documents folder, and then with saving data that I had a problem with to test it.


2013-08-30 23:49:11.323 XP Tracker[8311:15503] initMethod
2013-08-30 23:49:11.344 XP Tracker[8311:15503] viewDidLoad
2013-08-30 23:49:11.344 XP Tracker[8311:15503] viewWillDisappear
2013-08-30 23:49:11.345 XP Tracker[8311:15503] viewWillApear


So going off of gnasher729 reply I ran the test and discovered that I was putting the "LoadMyPlist", in viewController2, in the viewDidLoad method and putting my "saveMyPlist" in the viewWillDisappear method in viewController 1. It then became clear that I was loading my data before I was even saving it. So, if I am right and this is not an asynchronous task it should lock up the iPad until it finishes writing the data.

My hesitation with the while loop comes after reading the docs for the writeToFile: method. That method returns a BOOL and if that method fails to write the data then I created an infant loop which could lock up the program. Not to mention that the while loop 'should' not get executed until the line of code above returns a YES or NO response. So a while loop might not be a good idea to have here to be save.


BOOL saved = [myDict writeToFile: YES];
while(!saved){
keep infinite loop going...
}

Please correct me if I am wrong, I am here to learn and enjoy programming.

Thanks and by the way it looks like I accidentally submitted this on the OSX and not the ios forum, sorry.

multinode
Sep 1, 2013, 01:38 AM
I do see what you are saying using the while loop till it is competed. But from what I learned in programming class even Object C is 'kind of' a procedural language. What I mean by that is even though a method is called it drops down line by line executing the code till the method exits.

Since I don't dispatch writeToFile: method on a separate thread it should finish the task before proceeding to the next line of code.


Not exactly correct for two reasons:
1. the writeToFile line may be executing asynchronously so that the following line may execute before the write is completed. In fact, clearly things are happening "under the covers" before the write has completed. That's the source of your problem in the first place. ;)
2. compiler optimization may alter the code ordering if the compiler thinks the altered ordering doesn't change your functionality.


I was little confused about the order of method calls when you push a new viewController on the stack. There are at least 3 methods called on a new VC when instantiated.

initWithNibName:
viewDidLoad
viewWillAppear:


and when your old viewController calls the viewWillDisappear:

So I put an NSLog in each method without having any data written to the Documents folder, and then with saving data that I had a problem with to test it.

So going off of gnasher729 reply I ran the test and discovered that I was putting the "LoadMyPlist", in viewController2, in the viewDidLoad method and putting my "saveMyPlist" in the viewWillDisappear method in viewController 1. It then became clear that I was loading my data before I was even saving it. So, if I am right and this is not an asynchronous task it should lock up the iPad until it finishes writing the data.

My hesitation with the while loop comes after reading the docs for the writeToFile: method. That method returns a BOOL and if that method fails to write the data then I created an infant loop which could lock up the program. Not to mention that the while loop 'should' not get executed until the line of code above returns a YES or NO response. So a while loop might not be a good idea to have here to be save.


BOOL saved = [myDict writeToFile: YES];
while(!saved){
keep infinite loop going...
}

Please correct me if I am wrong, I am here to learn and enjoy programming.

Thanks and by the way it looks like I accidentally submitted this on the OSX and not the ios forum, sorry.


I have a basic problem with all of your "solutions" ... assumptions about what Apple is doing "under the covers" ... none of which is documented and thereby guaranteed to not change. :( Do you really know that the ordering of the functions called by Apple will stay that way forever??

You, the programmer must be in control regardless of what Apple does. The while (!saved) {
} does that. Finally, if you are worried about getting hung up in the while loop if "saved" never goes to TRUE, you could put a timer in the while(!saved){
} loop to break out and do something corrective of your choice.

gnasher729
Sep 1, 2013, 09:53 AM
2. compiler optimization may alter the code ordering if the compiler thinks the altered ordering doesn't change your functionality.

That is absolutely true, but as a programmer you can completely ignore it, since it will never change functionality.

It is sometimes important for benchmark writers. If the compiler figures out that you do the exact same calculation 100 times (to measure how long it takes), and it doesn't change the functionality whether you do it 100 times or only once, then the compiler may decide to do this only once, making it appear as if the benchmark ran extremely fast.

For example:

for (i = 0; i < 1000000; ++i) memset (myarray, 0, 1000000);

can be transformed by the compiler into

memset (myarray, 0, 1000000);
i = 1000000;


which runs about a million times faster.

xStep
Sep 1, 2013, 01:48 PM
I'm surprised there was any question of if writeToFile is asynchronous. It is synchronous. First the docs don't mention it either way. Second the description for the return type clearly indicates its purpose. That purpose can't be achieved with an asynchronous call.


larswik, you figured out your issue was in the sequence of method execution. Problem solved, unless you really think Apple will change that some day.


As for the optimizer. I've had issues with it in the past. Apps working fine with it off, and then acting up with full optimization on. Due to time, we never did track down one of them. I'm trying to dig up some code from over a year ago because this thread has made me curious what that optimization issue was.

chown33
Sep 1, 2013, 01:53 PM
Not exactly correct for two reasons:
1. the writeToFile line may be executing asynchronously so that the following line may execute before the write is completed. In fact, clearly things are happening "under the covers" before the write has completed. That's the source of your problem in the first place. ;)

First, there's no writeToFile: method on NSDictionary. There is a writeToFile:atomically:, so I assume that's what was intended.

Second, I see no logical way that writeToFile:atomically:YES could possibly be asynchronous. From the reference docs:
If flag is YES, the dictionary is written to an auxiliary file, and then the auxiliary file is renamed to path. If flag is NO, the dictionary is written directly to path. The YES option guarantees that path, if it exists at all, won’t be corrupted even if the system should crash during writing.

When the flag is YES, the last operation performed is to rename the aux file. But in order to do that, the write must have completed successfully, otherwise the rename would be wrong. Logically, it's incorrect to replace a prior file with one that wasn't written correctly.

Also, when the flag is YES, it's necessary for the rename to complete successfully, otherwise the return value indicating overall success (a boolean) for the method can't be determined. That is, one can't logically assert YES or NO for overall success without knowing the result of the rename. Why? Because if the rename fails, then the overall success is NO. So clearly, for the return value to be determinate, the rename must be completed.

So when writeToFile:atomically:YES returns, it is definitely completed, and there is no logical way that anything asynchronous can retroactively change the result returned from the method. Any subsequent while loop testing the returned value will never see a different value. It can't possibly do so, if the function isn't being called again. If the function isn't called again, then there's no way the returned value could change.


Since you originally posted pseudo-code, please post an actual worked-out examply of real code that illustrates a synchronizing save barrier. The two-line pseudo-code just isn't enough detail.

gnasher729
Sep 1, 2013, 02:29 PM
As for the optimizer. I've had issues with it in the past. Apps working fine with it off, and then acting up with full optimization on. Due to time, we never did track down one of them. I'm trying to dig up some code from over a year ago because this thread has made me curious what that optimization issue was.

The most common reason is code that is broken, but works by coincidence depending on what exactly the compiler does. If it doesn't work without optimisation, then you notice it while you write the code and fix it and think nothing on it. If it doesn't work _with_ optimisation, then you might have problems figuring out where you added the broken code, so you blame the optimiser.

But just in a recent thread someone write something like

assert (fread (..., n) == n);

and in a non-debug build this doesn't actually call fread!

larswik
Sep 1, 2013, 04:33 PM
larswik, you figured out your issue was in the sequence of method execution. Problem solved, unless you really think Apple will change that some day.


xStep - I just simply meant that all things seem to change and learning to program is a like hitting a moving target. When I started to learn there were no @properties and I had to release anything I NARC'd (New,Alloc, Retain,Copy). Now I code with ARC and I am using Properties more and more.

Even the basics like C under go revisions. Last year when trying to help a friend with some C code I was unable to declare a variable in a for loop. He had an old version of C but I thought C was C.

for(int i = 0 ; i < 10 ; i++)


We had to declare outside of the for loop for it to work and that is when I discovered even C has revisions.


int i;
for (i = 0; i < 10; i++)


As for my original writeToFile: I did mean writeToFile:atomically:YES I was just using a short hand assuming people who responding would know what I meant.

But as far as my original questions gnasher729 suggestion helped me see what was happening and I added the code to the correct area. I also added this code in the viewWillDisappear:

int x = 0;
while (x != 10000) {
NSLog(@"Count: %d", x++);
}


It took a full 5 seconds to print all those NSLogs on the screen before the new view was pushed on the stack. So when a new view is exicuted it first init's everything then viewDidLoad method is called. Then it went back to the viewWillDisappear: on the first VC and executed my while loop which took 5 seconds. Lastly it executed the ViewWillAppear: on the second VC and my second view appeared.

So this cemented the synchronous method writeToFile:atomically:YES would finish before the second view would be pushed on the stack. Even though the second view was loaded, it would not appear before the viewWillDisappear: was executed on the first VC.

Thanks!

multinode
Sep 1, 2013, 07:13 PM
I'm surprised there was any question of if writeToFile is asynchronous. It is synchronous. First the docs don't mention it either way. Second the description for the return type clearly indicates its purpose. That purpose can't be achieved with an asynchronous call.


I believe that you're reading too much into the BOOL return. That return merely notes whether or not the file write is SUCCESSFUL. If the file is very long, the write could take a long time. That would mitigate in favor of an asynchronous operation ... it is likely that Apple offloads the file write to another system thread. And the programmer's code continues beyond the write line. I/O is typically done that way because a synchronous operation would block until completion :(

From the docs Apple's ATOMIC seems to mean create and write to another (auxiliary) file in the same destination directory and then replace the original destination with the auxiliary file (renamed to that original file). "Under the covers" Apple might be using locks around the replacing and renaming operations. This meaning of the word ATOMIC doesn't preclude asynchronousity of the file write on another (system) thread.

An asynchronous write could return TRUE or FALSE depending upon whether the operation is SUCCESSFUL. Larswik could easily check my thinking by writing a VERY LARGE test file and putting a counter in while (!saved){
int i=0; i<10,000,000; i++);
}.

Larswick's out of order saving and subsequent loading of data suggests asynchronousity of the file write, but, in truth he hasn't told how much housekeeping is done in his BoilerPlate code prior to the write. That housekeeping code is not necessarily atomic.

Finally, mywhile does guarantee synchronousity with regard to the saving of his data and prevents the entire operation of launching the 2nd VC until the save is completed. Pretty extreme ... yes. So be it ... Larswik is depending upon the save to be completed prior to his loading.

I still don't like depending upon undocumented coding from Apple ... the company is not known for forthrightness in its changes. I've been bitten by "their code will never change because that would break many apps" ... changed anyway!

A better user experience might be to allow VC2 to appear and REFRESH its data with a notification that executes when SAVED returns TRUE (or do some corrective action if SAVED returns FALSE).

multinode
Sep 1, 2013, 08:13 PM
I see no logical way that writeToFile:atomically:YES could possibly be asynchronous. From the reference docs:
If flag is YES, the dictionary is written to an auxiliary file, and then the auxiliary file is renamed to path. If flag is NO, the dictionary is written directly to path. The YES option guarantees that path, if it exists at all, won’t be corrupted even if the system should crash during writing.

When the flag is YES, the last operation performed is to rename the aux file. But in order to do that, the write must have completed successfully (yes, but not necessarily immediately), otherwise the rename would be wrong. Logically, it's incorrect to replace a prior file with one that wasn't written correctly.

Also, when the flag is YES, it's necessary for the rename to complete successfully, otherwise the return value indicating overall success (a boolean) for the method can't be determined. That is, one can't logically assert YES or NO for overall success without knowing the result of the rename. Why? Because if the rename fails, then the overall success is NO. So clearly, for the return value to be determinate, the rename must be completed.

So when writeToFile:atomically:YES returns, it is definitely completed, NO and there is no logical way that anything asynchronous can retroactively change the result returned from the method. Any subsequent while loop testing the returned value will never see a different value (I don't agree). It can't possibly do so, if the function isn't being called again. If the function isn't called again, then there's no way the returned value could change.

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.

chown33
Sep 1, 2013, 09:04 PM
Asynchronousity doesn't mean immediate COMPLETION ... it means allowing following code to execute PRIOR to the asynchronous code's completion. I guess I could say immediate RETURN (maybe) but not immediate COMPLETION.

It's not possible to allow code following the return to execute without a definite YES or NO. The method does not have a third "indeterminate" state. The boolean is either YES or NO, and it indicates success. It's simply not possible to return a YES unless the entire operation has completed successfully.

If the method returns YES, and the return thereby allows subsequent code to execute, it is completely impossible to change that YES to a NO if the actual saving is completing asynchronously and that saving fails. There is no possible way that executing after the method returns can be "taken back" and started over. There is no speculative execution here once the method returns.

The method is clearly designed for synchronous operation and completion, not asynchronous. The documented return value doesn't say that YES indicates successful enqueueing for eventual completion, it says YES indicates a successful result, period.

If you think speculative or deferred execution is possible, please explain exactly how that would work after the method returns. The nature of returning to the caller is that the caller regains control. There is simply no way to return to the caller while also retaining control. And since returning to the caller requires a definite YES or NO at the point of return, it's logically impossible to defer anything that might cause a YES to become NO or a NO to become YES.

Since you don't agree, it's up to you to explain how this could possibly be done asynchronously. Not a general explanation, but a specific one. Whether Apple does it according to your explanation or not is irrelevant. I assert that it's logically impossible to do what you say, for the given API and the defined semantics of Objective-C message passing.

multinode
Sep 1, 2013, 09:25 PM
Ok ... I accept your challenge. :)

Returning immediately, but NOT completing immediately could be effected by offloading the entire writing (and renaming) to a different system thread ... thus allowing Larwik's following code to continue executing. Atomicity doesn't imply synchronousity and Apple's use of the word ATOMIC in the docs doesn't even imply the usual meaning of ATOMIC. An atomic operation means to me that whatever multiple instructions implement that operation, no other of my code can execute inside of the atomic code. My code will execute before or after the atomic code block. But parallelism of the atomic code and my code (on different threads) is not precluded.

Your turn. :)

It's not possible to allow code following the return to execute without a definite YES or NO. The method does not have a third "indeterminate" state. The boolean is either YES or NO, and it indicates success. It's simply not possible to return a YES unless the entire operation has completed successfully. This is true, but an asynchronous operation doesn't complete IMMEDIATELY. Question for you ... what exactly is your understanding of asynchronousity?

If the method returns YES, and the return thereby allows subsequent code to execute no, an asynchronous operation allows following code to execute BEFORE it COMPLETES, it is completely impossible to change that YES to a NO if the actual saving is completing asynchronously and that saving fails. There is no possible way that executing after the method returns can be "taken back" and started over. There is no speculative execution here once the method returns.

The method is clearly designed for synchronous operation and completion, not asynchronous. The documented return value doesn't say that YES indicates successful enqueueing for eventual completion, it says YES indicates a successful result, period.

If you think speculative or deferred execution is possible, please explain exactly how that would work after the method returns. The nature of returning to the caller is that the caller regains control. There is simply no way to return to the caller while also retaining control. And since returning to the caller requires a definite YES or NO at the point of return, it's logically impossible to defer anything that might cause a YES to become NO or a NO to become YES.

Since you don't agree, it's up to you to explain how this could possibly be done asynchronously. Not a general explanation, but a specific one. Whether Apple does it according to your explanation or not is irrelevant. I assert that it's logically impossible to do what you say, for the given API and the defined semantics of Objective-C message passing.

chown33
Sep 1, 2013, 09:54 PM
Ok ... I accept your challenge. :)

Returning immediately, but NOT completing immediately could be effected by offloading the entire writing (and renaming) to a different system thread ... thus allowing Larwik's following code to continue executing. Atomicity doesn't imply synchronousity and Apple's use of the word ATOMIC in the docs doesn't even imply the usual meaning of ATOMIC.

If a system thread is being used to complete the write (and renaming), then Larswik's thread must be blocked, in order to prevent a return to the caller of the method. If Larswik's thread is blocked, then it's not running, and there isn't a return to the caller. This means that no code after the return to caller executes.

If Larswik's thread isn't blocked, then the method can't determine a definite YES or NO to return to the caller, because the operation hasn't completed yet. If it does a spin-lock (e.g a while loop) or it actually suspends the thread is irrelevant. It must not return to the caller until a definite YES or NO is determined. There can be no definite YES or NO until the system thread has completed its operations. So while there may be a system thread completing the operations, Larswik's thread cannot (indeed, must not) return to the caller until the operations are complete. Again, this means that no code after the return to caller executes.

The API for the method simply doesn't have a way to signal completion other than the returned YES or NO value. There isn't any way for the caller to test for completion except by testing the YES/NO value. Since that value is effectively in a CPU register on return (look up the Objective-C binary calling conventions), there's no way that any system thread is going to be able to jump in and change a YES to a NO or vice versa. Since you apparently think otherwise, please explain exactly how that happens. Post actual example code showing not only the test of the returned YES/NO value, but what happens in the loop that is related in any way to an asynchronous completion you're postulating.


As to my understanding of asynchronicity, I've worked on various versions of the Unix kernel starting with Unix v7. I have also written several different multitaskers from scratch: cooperative, pre-emptive, prioritized, etc. for different CPUs such 6809, Z-80, 68K family, Intel x86 family, Atmel AVR, and probably some I've forgotten. I've worked on hard real-time systems, soft real-time systems, and some where real-time was just a faint hope.

I don't consider blocking a thread, performing the operation on another thread, then waking the original thread to be truly asynchronous. It certainly isn't asynchronous from the calling thread's point of view, because no other code runs in that thread until the calling thread is unblocked. It may be asynchronous as far as other threads are concerned, but no other threads are executing the code that follows the return in the original thread. So to the caller of the method, the method effectively completes synchronously.

Note that I'm not saying that disk caches are necessarily flushed before returning to the caller. That's unnecessary, since any other thread (or the same thread) reading the file from disk will simply find the data in the disk cache. The disk and its cache is acting as a thread-safe storage for the data.


EDIT
You added:
An atomic operation means to me that whatever multiple instructions implement that operation, no other of my code can execute inside of the atomic code. My code will execute before or after the atomic code block. But parallelism of the atomic code and my code (on different threads) is not precluded
That description of atomic is irrelevant.

Read the docs for the method. It explains exactly what the flag means. You're making a grave mistake by inferring or imputing that anything else atomic is happening, simply based on the name of the method.

The operation on the file is atomic in the sense that if any error occurs during writing or renaming, then any existing file is left undisturbed and NO is returned. The entire operation completes successfull, or it doesn't. There is no intermediate or indeterminate state of partial completion. Think of it more like a COMMIT transaction on a database, where all operations of a transaction must succeed, otherwise the original state is reinstated.

multinode
Sep 1, 2013, 11:54 PM
Hello Chown33 ...

Sounds like you have good experience ... perhaps more than mine. I was the Exec. Director of The PARALLEL Processing Connection for many years in Silicon Valley and worked on NUMA systems implemented by SCI (Scalable Coherent Interface). At the hardware level we considered Sun's M-Bus system. So I'm familiar with atomicity down to the bus operation level.

Beyond our good backgrounds, though, you haven't answered my question: what is an asynchronous file operation?

Atomicity means that a given code operates as a single indivisible operation regardless of how many underlying assembly instructions are involved. Apple's docs referring to ATOMICITY simply tell me the extent of that indivisibility. In fact, it's only their USE of the word ATOMIC that implies indivisibility at all.

I think you are seeing return and completion as being identical ... I don't agree with that. I'm willing to be wrong ... show me.


From http://msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v=vs.85).aspx:
There are two types of input/output (I/O) synchronization: synchronous I/O and asynchronous I/O. Asynchronous I/O is also referred to as overlapped I/O.

In synchronous file I/O, a thread starts an I/O operation and immediately enters a wait state until the I/O request has completed. A thread performing asynchronous file I/O sends an I/O request to the kernel by calling an appropriate function. If the request is accepted by the kernel, the calling thread continues processing another job until the kernel signals to the thread that the I/O operation is complete. It then interrupts its current job and processes the data from the I/O operation as necessary.

Of course, I don't know exactly how Apple implements asynchronous file ops ... I merely suggested the offloading to a system, i.e. kernel thread.

multinode
Sep 2, 2013, 12:18 AM
Read the docs for the method. It explains exactly what the flag means. You're making a grave mistake by inferring or imputing that anything else atomic is happening, simply based on the name of the method.

I agree ... I was merely giving ground to you by allowing the name of of the method to imply more than was explicitly being said in the docs.

gnasher729
Sep 2, 2013, 03:36 AM
Of course, I don't know exactly how Apple implements asynchronous file ops ... I merely suggested the offloading to a system, i.e. kernel thread.

If you want asynchronous file operations, you just call a synchronous operation on a background thread. That's why you won't find any I/O operations that are asynchronous by themselves.

----------

The operation on the file is atomic in the sense that if any error occurs during writing or renaming, then any existing file is left undisturbed and NO is returned. The entire operation completes successfull, or it doesn't. There is no intermediate or indeterminate state of partial completion. Think of it more like a COMMIT transaction on a database, where all operations of a transaction must succeed, otherwise the original state is reinstated.

Or the app crashes, or someone unplugs the power cable, and the operation is either performed completely or the existing file is left undisturbed, but the method doesn't manage to return either YES or NO :D

multinode
Sep 2, 2013, 12:27 PM
If you want asynchronous file operations, you just call a synchronous operation on a background thread. That's why you won't find any I/O operations that are asynchronous by themselves.



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.

Microsoft doesn't seem to agree with you ... from http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx::

In some cases, this delay (with synchronous I/O) may be unacceptable to the application's design and purpose, so application designers (that's us making the choice) should consider using asynchronous I/O with appropriate thread synchronization objects such as I/O completion ports.

A process opens a file for asynchronous I/O in its call to CreateFile by specifying the FILE_FLAG_OVERLAPPED flag in the dwFlagsAndAttributes parameter. (That's code we write.) If FILE_FLAG_OVERLAPPED is not specified, the file is opened for synchronous I/O. When the file has been opened for asynchronous I/O, a pointer to an OVERLAPPED structure is passed into the call to ReadFile and WriteFile. When performing synchronous I/O, this structure is not required in calls to ReadFile and WriteFile.

See also asynchronous I/O in http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlf101a.doc%2Fxlfopg%2Fasynio.htm

and http://man7.org/linux/man-pages/man7/aio.7.html

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.

Catfish_Man
Sep 2, 2013, 02:28 PM
If you want asynchronous file operations, you just call a synchronous operation on a background thread. That's why you won't find any I/O operations that are asynchronous by themselves.

Synchronous IO on a background thread is somewhat problematic, actually. Doing it on a global queue invites running into the GCD thread cap (64 threads), and even if you don't manage that it's wasting resources.

dispatch_io provides a proper asynchronous IO API, which is also available in a few places in higher level APIs (NSFileHandle's -readInBackgroundAndNotify: uses it, for example).

xStep
Sep 2, 2013, 03:18 PM
I believe that you're reading too much into the BOOL return. That return merely notes whether or not the file write is SUCCESSFUL.

I read the contract (documentation) and without further evidence or speculation have chosen the only reasonable path which is to believe it.


If the file is very long, the write could take a long time. That would mitigate in favor of an asynchronous operation ... it is likely that Apple offloads the file write to another system thread. And the programmer's code continues beyond the write line. I/O is typically done that way because a synchronous operation would block until completion.

Correct, the method we are discussing blocks the caller until the call has completed. It is a typical file I/O call.


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 the one jumping to that conclusion. We're in an Apple programming oriented thread. Why assume more than the domain we are in?

chown33
Sep 2, 2013, 03:36 PM
Beyond our good backgrounds, though, you haven't answered my question: what is an asynchronous file operation?


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.

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. 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. 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.

There is no other logical alternative for this method, given the design of C, Objective-C, and the binary calling conventions used. 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. It's impossible for code that would execute after the return to execute while the method is completing asynchronously. The simple fact is there's nothing in the design of this method that separates completion from return, therefore it must be synchronous.

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.

----------

If you want asynchronous file operations, you just call a synchronous operation on a background thread. That's why you won't find any I/O operations that are asynchronous by themselves.

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'.

gnasher729
Sep 2, 2013, 04:11 PM
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
Sep 2, 2013, 09:05 PM
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.

multinode
Sep 2, 2013, 09:30 PM
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
Sep 2, 2013, 09:51 PM
[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
Sep 2, 2013, 10:12 PM
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
Sep 2, 2013, 10:36 PM
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
Sep 2, 2013, 11:36 PM
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
Sep 3, 2013, 05:29 PM
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
Sep 3, 2013, 08:33 PM
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. (http://forums.macrumors.com/showpost.php?p=17816624&postcount=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: (http://forums.macrumors.com/showpost.php?p=17817417&postcount=14)
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. (http://en.wikipedia.org/wiki/Asynchronous_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
Sep 3, 2013, 09:15 PM
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