What's New in Director 8.5 > Multiuser Server-Side Scripting > Multithreading

 

Multithreading

In order to enhance performance in situations where large numbers of movies are executing server-side scripts simultaneously, the server supports cooperative multithreading. Cooperative multithreading allows the scripts of many movies to execute at the same time. This prevents one movie from having to wait for all the movies ahead of it to finish their script processing before being able to process its own scripts on the server.

The type of multithreading supported by the server is known as cooperative multithreading because the different threads, or script processes, take turns using the computer's CPU in a cooperative manner. While one thread can issue a command to block another thread from executing for a period of time, the default behavior of the server's threads is to share the CPU equally.

Threads are particularly advantageous when your server-side scripts are executing complex or repetitive tasks or during development, when your code may produce errors. By using threads, you can prevent script errors or repetitive tasks from getting in the way of tasks running in other threads. Note that the Dispatcher script runs in the main thread that starts when the server launches.

To take advantage of multithreading, a script must first create a new thread with the thread().new() command. Once the new thread is created, subsequent handlers that are called may be assigned to the thread so that they execute within it.

The following script contains two handlers. The first creates a new thread, and the second is executed in the newly created thread:

on makeNewThread me
	theThread = thread().new("testThread")
	-- get a random number by assigning the calculateRandomNumber
	-- handler to the newly created thread
	theNumber = theThread.call(#calculateRandomNumber, me)
end

on calculateRandomNumber me
	a = random(999)
	return a
end

In this example, the calculateRandomNumber handler is assigned to the thread named testThread. It runs in that thread and allows other handlers assigned to other threads to run simultaneously. You can choose to have all the handlers in a movie's server script run in one or more threads.

 
Sharing data between threads

Once one or more threads exist, they can share information with each other. To have one thread pass a value to another single thread, use the produceValue() function. The following handler runs in a thread named testThread, assigns a value to the variable testValue, and makes the value available to another thread with the produceValue() function:

on sendValue
	testValue = 123456
	testThread.produceValue(testValue)
end

The thread testThread will stop running until another thread accesses the value by using awaitValue(). The following handler runs in its own thread and accesses the value testValue from the thread testThread:

on retrieveNumber
	testThread.awaitValue()
end

The thread containing this handler will also stop running until the value is produced by the thread named testThread.

The produceValue() and awaitValue() commands are useful for a single thread sharing data with a single other thread. To have a thread send a value to more than one other thread, use the lock(), wait() and notifyAll() commands. These commands work only on lists, so you must place the data you want to share into a linear list or a property list.

Use these steps to send data from one thread to several other threads:

1

Use the lock() command in the thread that will be editing the list to prevent any other thread from accessing the list while the first thread is editing it.

myList = [12, 32, 43, 34, 45]
lock(myList)

2

Use the wait() command in every other thread that you plan to have receive the new value of the list. These threads will stop executing until the new value of myList becomes available.

wait(myList)

3

In the original thread that locked the list, edit the value of the list. The editing of the list must be limited to changing, adding, or deleting individual values from within the list.

For example, the following Lingo edits only the 4th value inside the list named myList:

myList[4] = 66

The result is a list that looks like this:

myList = [12, 32, 43, 66, 45]

Do not set the list to a whole new list, as shown in the following Lingo:

myList = [1, 2, 3, 4]

This will result in the lock that was originally placed on myList in step 1 being removed. Other threads could then edit the list themselves while the original thread is editing it, producing unpredictable results.

4

Use the notifyAll() command on the list in the original thread to pass the new value of myList to all the threads that are waiting on it.

notifyAll(myList)

Threads can also call handlers in other threads, report their status, and start and stop their operations on command. For more information, see Multiuser Lingo Dictionary overview.