-1

Noob question here on C++ classes.

I have function A that can be called many times, and each time it's called it creates a new thread with function B. Function b calls function C, which does a lot of processing calling many Win32 APIs, with data all local to function C.

Q: does moving function C into a class and declaring it as a New from within function B solve any thread-safe issues? In other words, because fncC() exists at the same address in the memory address of the program, I'm concerned that if multiple functions call it simultaneously the program will crash.

fncA()
{
_beginthreadex(...fncB)
}

fncB()
{
fncC()
}

fncC()
{
RegCreateKeyEx(...)
}
Hot Licks
  • 47,103
  • 17
  • 93
  • 151
JeffR
  • 765
  • 2
  • 8
  • 23
  • 3
    I don't know how you declare something "New". – Hot Licks Oct 10 '13 at 22:34
  • 1
    Thread safety has to do with shared mutable -state-, not threads per se. Functions, at least in OO parlance, do not have state (they often operate on it). Whenever you have fields or variables that are accessed by more than one thread, there is the possibility that the application is not thread-safe. As such, I can't say whether your functions are thread-safe because I need to know what application or object -state- they are accessing. Thread confinement is a valid multithreading strategy. If all your state is truly confined to the thread in which fncC is called, then it could be safe. – scottb Oct 10 '13 at 22:41
  • To add to what @scottb says, don't think for a minute that thread safety is just a matter of adding a bit of syntactic sugar. – user207421 Oct 10 '13 at 23:34

3 Answers3

0

It may or may not, is depends on what the class actually does.

Whether the code is implemented as a standalone function or as a method of a class, the code is still executed in whatever thread context calls it. Putting it in a class serves to introduce the hidden this parameter into the method calls. You still have to deal with thread concurrency issues if multiple threads are using the same class instance at the same time. On the other hand, if the method is only accessing data that belongs to the class, and each thread is operating on a different instance of the class, then that is generally safe. Concurrency issues occur when multiple threads are accessing the same data/resource at the same time.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • So if fncC(TCHAR *sValue) is called w/o classes from multiple running threads, does each thread have it's own "copy" of the function C whereby if data "a" was sent by one thread and data "b" was sent by another thread, would function C start with "a", then in the middle of processing, use "b"? – JeffR Oct 10 '13 at 22:46
  • Each thread has its own stack. The sValue *pointer* would be a local variable in fncC but the entire string would not be copied. The function C is not copied. You seem to be confusing variables and program instruction memory – Pete Oct 11 '13 at 00:28
  • Local variables can be considered to only exist for a single run of a function. They are either placed in a register or on the stack. If the function is executed concurrently then the other thread will have its own local variables – Pete Oct 11 '13 at 00:33
0

If FncC uses only local data, and calls thread-safe methods, then FncC is thread-safe.

If FncC calls even a single thread-unsafe method, then FncC is NOT thread-safe.

If FncC accesses any data beyond the scope of the method, without proper protection -- e.g. static data, global data, class member data, without properly using a mutex -- then FncC is NOT thread-safe.

Shamelessly linking to my previous answer about Thread Safety: how to make an application thread safe?

Community
  • 1
  • 1
Tim
  • 8,912
  • 3
  • 39
  • 57
0

Unless your implementation of class C's member functions uses self modifying code (unlikely), then accessing the program memory itself is not going to be a problem. Your problem is going to be access of shared mutable data and resources.

If I understand the question correctly you are saying that you would be creating a new instance of a class 'C' and exclusively calling come member function of class C from another thread.

e.g. psuedocode:

void thread1() {
   auto_ptr<C> pc(new C());
   while (1) {
      pc->f();
   }
}
void thread2() {
   auto_ptr<C> pc(new C());
   while (1) {
      pc->f();
   }
}

Since the code in function C::f() does not change it is safe to execute it concurrently.

However if the code in C::f() accesses any shared data then it is not safe unless you put in thread synchronization.

If, for example C::f() looked like this and C has a member variable 'int i_' then this is safe provided no other threads change the value:

void C::f() {
    ++i_;
}

That is only safe if no other threads read or modify that instance of C's 'i_' member. In some cases it might be safe if only other threads read i_ but that is only if you can guarantee that writes to i_ are atomic. There are further caveats there to do with instruction ordering and what you might expect elsewhere in a program so any reliance on stuff like that needs extreme care. In this contrived example, no other threads are going to know about the instance of 'C' so it will be fine.

If C::f() looked like this:

void C::f() {
    static int i = 0;
    std::cout << i++ << std::endl;
}

Then it is definitely NOT safe. The static int is shared data - all calls to C::f have access to the same data regardless of what instance it is. There are data races with the static initializer for 'i' (setting it to zero for the first time for which the compiler will insert some bookkeeping data). Additionally the increment of 'i' is likely to not be an atomic operation -- so it is not safe.

The use of the global variable std::cout here is also not thread safe. Even if the output stream implements a mutex internally, you are doing two separate operations here and you could get races. If there is no thread synchronization internally on the output stream then you are likely to have all manner of undefined behaviour.

Pete
  • 4,784
  • 26
  • 33