• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
(Part 1) Thread-safety Concerns
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

(Part 1) Thread-safety Concerns


  • Subject: (Part 1) Thread-safety Concerns
  • From: Steve Klingsporn <email@hidden>
  • Date: Sat, 2 Nov 2002 23:47:13 -0600

Here is what I'm using threads for in my Cocoa-Java application, my justification for using them, and what I've encountered that can go wrong with Cocoa not being thread-safe. I'll also discuss my next planned project, why it needs threads, and why the user interface should be thread-safe (one way or another).

- I use a "Listener" thread subclass that is associated with a ServerSocket. The thread blocks on the "accept()" method, which listens on an incoming port for game connection requests. The thread continues when an incoming connection is received, calling the constructor for my "Connection" thread subclass, which takes the socket from the Listener and blocks on a socket read.

- I use a "Connection" thread subclass that is associated with a Socket. The thread blocks on a "readLine()" call from my BufferedReader that is associated with the input stream for this socket. Since Java 1.3.1 and earlier don't have non-blocking I/O, you need to associate a thread with a socket to have an acceptable user experience.

- I use a "MoverThread" thread subclass that is associated with my "AtaxxView" NSView subclass that draws my game board. The "MoverThread"'s job is to wait() on a boolean, and when a move is "push()"ed to the MoverThread, notify() is called, the thread takes care of animating the move (from the computer, computer demo, or opponent Connection.

- I use a "RosterThread" thread subclass that periodically opens a socket connection to a "roster server" at some known address. The purpose of the RosterThread is to update the user's name, display comment, and IP address before the roster server removes the user's entry from the Hashtable of users. RosterThread sleep()'s between the time it is called on to do something and the next polling interval.

Here are where these threads need to interact with the user interface from the thread-side, instead of due to some user interaction in the UI:

Listener needs to cause a sheet to be thrown up to ask the user if she wants to accept an incoming connection after the proper handshake message is received from the socket. Throwing up a sheet is not a thread-safe operation. Sometimes it works, and sometimes Cocoa crashes somewhere in the Objective Sea. This is an operation that can "elegantly" be implemented using an application-defined NSEvent subtype, so I handle this situation in this manner.

Connection sends incoming one-liner "messages" to the members of its "handler" vector, which implement the "MessageHandler" interface. In this case, the handler is AtaxxController, my way-too-overloaded controller class that manages interaction between the game, "AtaxxNode" (the platform-independent network class), and "AtaxxGame" (the platform-independent game model). Connection can generate messages that necessitate that the game board be updated. These appear to be thread-safe in that they do drawing into an offscreen NSImage and then call display() or displayRect() on my "AtaxxView" NSView subclass. I cannot safely implement this functionality with custom NSEvents because if the user is doing other things, the events can arrive late, well up, or (nightmare scenario) perhaps not at all. The result is a clumsily-updated board view and jittery game experience. Therefore, I leave these called from the Connection thread, and all seems to be well. Updating the score NSTextFields, of which there are 2 for each player, overlaid atop each other to provide the "etched" look atop my brushed metal textured window is not thread-safe. I do three things to these when I update the scores: I call setStringValue() on each pair of NSTextField instances to set the name, score, wins and matches played, and I change the colors of each pair, either making them look darker in front or "etched" by messing with their colors. Then, I call display() on them, because sometimes for some reason, they get a little visually out of sync, and the illusion is blown. Something here is not thread-safe, so I'm going to have to move these into NSEvent land.

Connection also can receive incoming chat messages. Incoming chat messages get spliced with the user's name, turned into a NSAttributedString, and appended to my conversation NSView. I then scroll the NSTextView to the bottom so the user doesn't have to manually scroll the view in order to read what was said. It appears (though I have read differently) that appending the NSAttributedString is okay to do from the Connection thread, but I often get into problems scrolling the conversation NSTextView, so I moved the scrolling part into NSEvent land. I could move the append there as well and store the NSAttributedString in a Vector of them, but this doesn't seem to crash or anything, so I haven't done so. If I scroll the view from the Connection thread while clicking on the enclosing NSTabView, my app explodes, so I scroll from NSEvent land.

Roster updates can cause the NSTableView that shows the users online on the roster server's data source to update. I do this from NSEvent land. Something is still blowing up in my NSTableView on application launch, but this is happening to other people on cocoa.mamasam.com (one of the two mailing lists). There haven't been any good answers or resolutions to these people's problems, so I assume it's a Cocoa bug. It's hard to reproduce, happens very rarely, generally at start-up, so I keep an eye out for it, but I don't assume it's a threading issue as it happens from the main thread.

So a lot of stuff is going on in my app at any given time. 99% of the time, everything's cool. Every once in a while, something blows up and it's generally hard to track down because it won't happen again for some time, and when it does happen, I invariably don't have System.out.println()'s sprinkled in the right places to find out where I am. Looking at the Objective C stack traces in my crash logs helps somewhat to determine where things went bad, but upon looking at my code, I can't find where the problems are. I will find them, but it's a lengthy process. My conscience burns when my wimpy $5 app that I've spent a good deal of time and energy on bombs the app. Java's not supposed to do this.
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.
  • Follow-Ups:
    • Re: (Part 1) Thread-safety Concerns
      • From: Chris Hanson <email@hidden>
  • Prev by Date: (Part 3) Thread-safety concerns
  • Next by Date: Link: Cocoa-Thread safety concerns
  • Previous by thread: (Part 3) Thread-safety concerns
  • Next by thread: Re: (Part 1) Thread-safety Concerns
  • Index(es):
    • Date
    • Thread