www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Are the _d_arrayappend functions, thread-safe?

reply Jeff Davey <jeffd gwava.com> writes:
I've recently been having problems with a small SMTP app when I have serious
multi-threaded load on linux (compiled with DMD 1.016).

At first, it started with anything that uses std.string.format, and dies in
_d_arrayappendcT.. so I removed all calls to anything that uses that module:


(gdb) bt





Die: DW_TAG_<unknown> (abbrev = 6, offset = 324)
        has children: FALSE
        attributes:
                DW_AT_byte_size (DW_FORM_data1) constant: 8
                DW_AT_type (DW_FORM_ref4) constant ref: 307 (adjusted)
Dwarf Error: Cannot find type of die [in module /root/smtp]


The next place this problem occurred is std.string.split, with again, the
_d_arrayappendcT function:

(gdb) bt


Die: DW_TAG_<unknown> (abbrev = 6, offset = 324)
        has children: FALSE
        attributes:
                DW_AT_byte_size (DW_FORM_data1) constant: 8
                DW_AT_type (DW_FORM_ref4) constant ref: 307 (adjusted)
Dwarf Error: Cannot find type of die [in module /root/smtp]


So, I removed the std.string.split calls, and wrote my own that pre-allocated
the array rather than appends to it, and that fixed that issue.

And then, somewhere else (where I just have a regular array append):
(gdb) bt


Die: DW_TAG_<unknown> (abbrev = 6, offset = 324)
        has children: FALSE
        attributes:
                DW_AT_byte_size (DW_FORM_data1) constant: 8
                DW_AT_type (DW_FORM_ref4) constant ref: 307 (adjusted)
Dwarf Error: Cannot find type of die [in module /root/smtp]

This time, it's in a slightly different function _d_arrayappendT.

Basically the software has about 200 receiving threads, and is receiving around
60mbit/s of network traffic in a stress test. 

It's definitely thread related, as running it with only one thread it performs
fine through 130,000 different emails.

The threading model is fairly simple, accept a socket, pass that socket to a
working thread, let the working thread clean up that socket. 

The only globals being used (other than anything in phobos) are contained to a
wrapper "SocketStream" class, that has private variables, and one stream per
class is created during the beginning of the work phase.

I'm "pretty" certain it's not something on my side, but I would like to be
mistaken.
Jun 18 2007
parent reply Sean Kelly <sean f4.ca> writes:
Looking at the code, it should be fine.  I don't suppose you're trying 
to append to a single array from >1 thread simultaneously?


Sean
Jun 18 2007
parent reply Jeff Davey <jeffd gwava.com> writes:
Sean Kelly Wrote:

 Looking at the code, it should be fine.  I don't suppose you're trying 
 to append to a single array from >1 thread simultaneously?
Nope. I was trying to track down possible memory corruption with valgrind.. but apparently valgrind doesn't deal with pausing the threads for the gc to go off (Gives "Unrecognized instruction 0x66 0x60 0xB9 0x20"). I had a look at the array append stuff myself, it looks like things are getting locked up properly, but I don't have enough knowledge to track this down. I guess I'll assume that there isn't any problems with std.string.format, and that I have some sort of memory error somewhere.
Jun 18 2007
parent reply Jeff Davey <jeffd gwava.com> writes:
Alright, I don't know if I can assume this anymore.

I've replaced the std.string.split call with this function (that pre-allocates
the array), and I can't get the app to segfault anymore.

	char[][] split(char[] data)
	{
		char[][] rtn;
		int lastPos = 0;
		int index = 0;

		int numSpaces = std.string.count(data, " ");
		rtn = new char[][numSpaces + 1];
		if (numSpaces > 0)
		{
			for (int i = 0; i < data.length; i++)
			{
				if (data[i] == ' ')
				{
					char[] word = data[lastPos .. i];
					rtn[index++] ~= data[lastPos .. i];
					lastPos = i + 1;
				}
			}
		}
		rtn[index] = data[lastPos .. data.length];

		return rtn;
	}


If I switch back to std.string.split, it dies in _d_arrayappendcT within
seconds with 200 threads going on a dual-core system.

I'm also able to get it to segfault if I modify the above function to do array
appends instead of pre-allocating the result.

I'm a bit at loss here, and starting to feel really uncomfortable with array
appends at this point in a multi-threaded app.


Jeff Davey Wrote:

 I guess I'll assume that there isn't any problems with std.string.format, and
that I have some sort of memory error somewhere.
Jun 19 2007
parent reply Jeff Davey <jeffd gwava.com> writes:
Ack, I pasted the wrong function (that one was a result of some debugging).

Here's the right one:

	char[][] split(char[] data)
	{
		char[][] rtn;
		int lastPos = 0;
		int index = 0;

		int numSpaces = std.string.count(data, " ");
		rtn = new char[][numSpaces + 1];
		if (numSpaces > 0)
		{
			for (int i = 0; i < data.length; i++)
			{
				if (data[i] == ' ')
				{
					rtn[index++] = data[lastPos .. i];
					lastPos = i + 1;
				}
			}
		}
		rtn[index] = data[lastPos .. data.length];

		return rtn;
	}

There might still be some issues with something else local, but I'm finding it
very strange that replacing std.string.split with that function, I'm no longer
segfaulting.
Jun 19 2007
parent Sean Kelly <sean f4.ca> writes:
Jeff Davey wrote:
 
 There might still be some issues with something else local, but I'm finding it
very strange that replacing std.string.split with that function, I'm no longer
segfaulting.
Same here. Sean
Jun 29 2007