1

I am working with a code base with some .C files and .CPP files.

The multiple threads in the system calls some functions in C files as the one given below.

void CalculateCrc(PWORD pwCRC, PBYTE pbyBuffer, DWORD dwBufferLen)
{
    WORD wFCS = 0xffff;

    ASSERT(pbyBuffer);
    ASSERT(pwCRC);
    while(dwBufferLen--)
    {
        wFCS = (WORD)(wFCS >> 8) ^ tbl_FCS[(wFCS ^ *pbyBuffer++) & 0xff];
    }
    wFCS ^= 0xffff; // complement
    *pwCRC = wFCS;
}

For each calling thread will there be copies of arguments[pwCRC, pbyBuffer, dwBufferLen] and non-static data members of function [WORD wFCS], or will there be only a single set of data shared by all threads that will result in data corruption and make the calls from multiple threads unsafe?

I am not a native English speaker. Forgive me if the question is not asked in a clear manner.

Thanks for your time.

0

3 Answers 3

3

I believe each thread will have its own stack, which is a copy of the spawning process' stack (I hope I am technically correct on this one). They do share address space and heap though.

So anything that existed before spawn will be shared. Anything created after is thread-local. And since everything is passed by value, and data member is non-static, it will be created thread-local.

Your function per-se is safe. However, since you work with pointers, you need to take care that two threads do not work over the same memory area. The variables are safe, the memory is not.

Sign up to request clarification or add additional context in comments.

Comments

1

The function will have its own copy of pwCRC and dwBufferLen BUT NOT pbyBuffer because you are passing it as a pointer.

I give two solutions:

A. ensure that all threads only have read (or no) access to pbyBuffer while this function is called; or (if the data is rather small

You could do this by making a copy.

B. Pass the buffer by value. you can do this by using a structure

struct buffer { char buffer [LEN] ; }

This only works if the buffer is small. If I remember correctly, the C++ standard limits the size of the call stack as a concession to the VAX architecture. Your compiler might exceed the limits of the standard. Even so, it is not a good idea to kill the stack with large arguments.

10 Comments

The function will have its own copy of pbyBuffer because it, like all parameters in C, is passed by value. Whether the memory pointed to by pbyBuffer is thread-local, we don't know. And passing the buffer by value only works if the buffer is shared but isn't ever modified by any of the threads ... otherwise it could be modified before or while being copied. In which case there is no point in copying it. And if there were, it could be copied and then a pointer to the copy could be passed ... which may be happening. There's simply no reason to change the signature ... that's confused.
I don't think the standard even specifies that there is a call stack, let alone what the minimum value for its maximum size might be. There typically is a limit, but its value is a QoI (Quality of Implementation) issue, not a standard specified value.
"If I remember correctly, the C++ standard limits the size of the call stack as a concession to the VAX architecture." -- You don't. The only thing remotely relevant about the VAX is that the layout of the stack frame was defined by the hardware, which had a fancy function call instruction.
@JonathanLeffler that's a weak point in the standard. Without a minimum guaranteed stack size, there are actually no strictly conforming programs that call functions.
@JimBalter: It's not a big problem — at least IMO. If the compiler doesn't provide enough stack to run your program, don't use it — get a better compiler, or bigger machine. There is no need for the standard to legislate the size. However, as I pointed out, the standard does not even mandate a stack (though every implementation actually uses one), so it is inappropriate for it to specify the size of something that it doesn't mandate the use of.
|
1

will there be copies of arguments[pwCRC, pbyBuffer, dwBufferLen]

In C, the arguments are passed by value, so for each call from different threads these will have different copied. However, if the passed variables are global/shared by the threads then all such threads will pass the same variables.

In your case PWORD pwCRC, PBYTE pbyBuffer are pointers. If these are shared between the threads then also, your function is not thread-safe. As multiple threads may try to change the value pointed by these pointers.

non-static data members of function [WORD wFCS]

Yes, there will be copy for each function call.

3 Comments

I was also thinking that multiple copies exist. But this [stackoverflow.com/questions/3177302/… thread makes me confused which I feel states otherwise.
@NeonGlow No it doesn't. They meant, that data is passed by reference, and if you spawn threads working on the same reference you will run into race conditions. That is what they meant by "the same variable", i.e. operating on the same memory location. Maybe it was not stated clearly enough. You are bringing new variables to life with each call. You will run into trouble if two threads will operate on the same/overlapping pwCRC and pbyBuffer. Otherwise it is safe.
@NeonGlow, in C++ that call (mentioned the question) is pass by reference, so if multiple threads are working on same variable passed to thread, that will not be good. Updated ans for some more info.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.