Noob有关C ++类的问题。
我有一个可以多次调用的函数A,每次调用它都会创建一个带有函数B的新线程。函数b调用函数C,它执行大量处理调用许多Win32 API,数据都是本地的功能C.
问:是否将函数C移动到一个类中并将其声明为函数B中的New解决任何线程安全问题?换句话说,因为fncC()存在于程序的内存地址中的相同地址,所以我担心如果多个函数同时调用它,程序将崩溃。
fncA()
{
_beginthreadex(...fncB)
}
fncB()
{
fncC()
}
fncC()
{
RegCreateKeyEx(...)
}
答案 0 :(得分:0)
它可能会也可能不会取决于班级的实际行为。
无论代码是作为独立函数还是作为类的方法实现,代码仍然在任何调用它的线程上下文中执行。将它放在一个类中可以将隐藏的this
参数引入方法调用中。如果多个线程同时使用同一个类实例,您仍然必须处理线程并发问题。另一方面,如果该方法仅访问属于该类的数据,并且每个线程在该类的不同实例上运行,那么这通常是安全的。当多个线程同时访问相同的数据/资源时,会发生并发问题。
答案 1 :(得分:0)
如果FncC
仅使用本地数据,并调用线程安全方法,则FncC
是线程安全的。
如果FncC
甚至调用单个线程不安全的方法,则FncC
不是线程安全的。
如果FncC
访问超出方法范围的任何数据,则没有适当的保护 - 例如静态数据,全局数据,类成员数据,没有正确使用互斥锁 - 然后FncC
不是线程安全的。
无耻地链接到我之前关于线程安全的答案:how to make an application thread safe?
答案 2 :(得分:0)
除非你的C类成员函数的实现使用自修改代码(不太可能),否则访问程序存储器本身不会成为问题。您的问题是访问共享的可变数据和资源。
如果我正确地理解了这个问题,你会说你将创建一个类'C'的新实例,并从另一个线程专门调用C类的成员函数。
e.g。伪码:
void thread1() {
auto_ptr<C> pc(new C());
while (1) {
pc->f();
}
}
void thread2() {
auto_ptr<C> pc(new C());
while (1) {
pc->f();
}
}
由于函数C :: f()中的代码没有改变,因此同时执行它是安全的。
但是,如果C :: f()中的代码访问任何共享数据,那么除非你进行线程同步,否则它是不安全的。
例如,如果C :: f()看起来像这样并且C有一个成员变量“int i_
”那么这是安全的,前提是没有其他线程改变该值:
void C::f() {
++i_;
}
只有在没有其他线程读取或修改C的'i_'成员的实例时,这才是安全的。在某些情况下,如果只有其他线程读取i_
,那么可能是安全的,但这只有在你可以保证对i_
的写入是原子的时才是安全的。还有进一步的注意事项与指令排序以及您在程序中其他地方可能会有什么期望,因此任何对此类内容的依赖都需要特别小心。在这个人为的例子中,没有其他线程会知道'C'的实例,所以没关系。
如果C :: f()看起来像这样:
void C::f() {
static int i = 0;
std::cout << i++ << std::endl;
}
然后绝对不安全。 static int是共享数据 - 对C :: f的所有调用都可以访问相同的数据,无论它是什么实例。 “i
”的静态初始化程序存在数据争用(第一次将其设置为零,编译器将插入一些簿记数据)。另外,'i
'的增量很可能不是原子操作 - 所以它不安全。
此处使用全局变量std::cout
也不是线程安全的。即使输出流在内部实现了互斥,你也可以在这里进行两个独立的操作,你可以参加比赛。如果输出流内部没有线程同步,那么您可能会有各种未定义的行为。