As more MapServer users begin to explore the Java and C# mapscript modules, there are more questions about thread safety. I spent a little time yesterday afternoon gathering what is known about MapServer's thread safety and summarizing it in the form of answers to frequently asked questions.
Q: Is MapServer thread-safe?
A: Generally, no (but see the next question). Many components of MapServer use static or global data that could potentially be modified by another thread. Under heavy load these unlikely events become inevitable, and could result in sporadic errors. Furthermore, instances of mapscript classes should never be shared between threads.
Q: Is it possible to safely use any of MapServer in a multi-threaded application?
A: Some of it, yes, with care. Or with Python :) Programmers must either avoid using the unsafe components of MapServer or carefully place locks around them. Python's global interpreter lock immunizes against MapServer threading problems; since no mapscript code ever releases the GIL all mapscript functions or methods are effectively atomic. Users of mapscript and Java, .NET, mod_perl, or mod_php do not have this extra layer of protection.
A: Which components are to be avoided?
Q: Below are lists of unsafe and unprotected components and unsafe but locked components.
- OGR layers: use unsafe CPL services
- Cartoline rendering: static data
- Imagemap output: static data
- SWF output: static data and use of unsafe msGetBasename()
- SVG output: static data
- WMS/WFS client connections: potential race condition in Curl initialization
- WMS/WFS server: static data used for state of dispatcher
- Forcing a temporary file base (an obscure feature): static data
- MyGIS: some static data
- ArcSDE support: connection information stored as static data
- PostGIS support: assumes all connections have the same byte order, which is stored as static data
Unsafe, but locked. The specific issue is noted:
- Map config file loading: global parser
- Setting class and and layer filter expressions: global parser
- Class expression evaluation: global parser
- Setting map and layer projections: PROJ.4 initialization
- Raster layer rendering and querying: GDAL library uses unsafe CPL services
- Database Connections: static connection information
Rather coarse locks are in place for the above. Only a single thread can use the global parser at a time, and only one thread can access GDAL raster data at a time. Performance is exchanged for safety.
So what can be done safely? Rendering features from shapefiles using the GD driver is safe. Raster data via GDAL is safe. PostGIS connections are fine so long as all return data with the same byte order. Projecting layers is safe. I'm working around the WMS client issue in several applications by fetching imagery using urllib and loading it into a MapServer imageObj with good results. This is good enough for my needs (PCL and ZCO). Most of the unsafe whizz-bang stuff (SWF, SVG) isn't implemented in a way useful to mapscript anyhow.