0

I am using GPARs asynchronous functions to fire off a process as each line in a file is parsed.

I am seeing some strange behavior that makes me wonder if I have an issue with thread safety.

Let's say I have a current object that is being loaded up with values from the current row in an input spreadsheet, like so:

Uploader {
  MyRowObject currentRowObject
}

Once it has all the values from the current row, I fire off an async closure that looks a bit like this:

Closure processCurrentRowObject = { ->
    myService.processCurrentRowObject (currentRowObject)
}.asyncFun()

It is defined in the same class, so it has access to the currentRowObject.

While that is off and running, I parse the next row, and start by creating a new object:

MyObject currentObject = new MyObject()

and start loading it up with values.

I assumed that this would be safe, that the asynchronous function would be pointing to the previous object. However, I wonder if because I am letting the closure bind to the reference, if somehow the reference is getting updated in the async function, and I am pulling the object instance out from under it, so to speak - changing it while it's trying to work on the previous instance.

If so, any suggestions for fixing? Or am I safe?

Thanks!

user1373467
  • 315
  • 3
  • 12

1 Answers1

1

I'm not sure I fully understand your case, however, here's a quick tip. Since it is always dangerous to share a single mutable object among threads, I'd recommend to completely separate the row objects used for different rows:

final localRowObject = currentRowObject currentRowObject = null

Closure processCurrentRowObject = { -> myService.processCurrentRowObject (localRowObject) }.asyncFun()

Vaclav Pech
  • 1,431
  • 8
  • 6
  • Thanks... it was just a bit trickier, I was creating a new object for each row, but the reference to that current object was a member variable. I changed it to make a copy of the object before calling (essentially) processCurrentRowObject(), and pass in that copy. I guess in my mind, I thought of the closure as a function unto itself, as long as it wasn't internally referencing things external to it and all was being passed in. In general, I've done a good job at isolating things within closures with a functional mindset, but I think the groovy closure binding got me here. – user1373467 Nov 15 '12 at 15:05
  • @Vaclav... one follow up question, if you don't mind... is the answer in this post (http://stackoverflow.com/questions/11529521/how-do-i-execute-two-tasks-simultaneously-and-wait-for-the-results-in-groovy?rq=1) really the best way to go to wait for a bunch of async functions to finish? It could be tens of thousands. Thanks! – user1373467 Nov 15 '12 at 15:07
  • I went ahead and posted my follow up as a separate question: http://stackoverflow.com/questions/13405806/gpars-report-status-on-large-number-of-async-functions-and-wait-for-completion – user1373467 Nov 15 '12 at 20:41
  • Just as a further note to any poor schleps that find their way here... I isolated this problem in a standalone test. If I pass in the variable to the closure, everything is fine - I make the async function sleep, change the reference in the main thread to point a new object, and the async function still uses the original object. If however, I don't pass the variable (currentRowObject) into the closure but reference the Uploader's member variable directly inside the closure, a change to it in the main thread does take affect (i.e., the async function picks up the new object from the ref). – user1373467 Nov 19 '12 at 19:17
  • It's more obvious now that I think about it, but I wanted to be sure that passing it into the closure was safe, and it is (if you change the sample code above to something like this): – user1373467 Nov 19 '12 at 19:19
  • Closure processCurrentRowObject = { passedRowObject -> myService.processCurrentRowObject (passedRowObject ) }.asyncFun() – user1373467 Nov 19 '12 at 19:20