传递“这个”到线程 c++
在 C++ 中执行以下操作的最佳方法是什么?虽然我当前的方法有效,但我不确定这是最好的方法:
1)我有一个主类,其中有一些函数
2)我有一个线程,它在套接字上接受一些指令,然后运行其中一个函数在主类中
3)有许多线程访问主类中的各种函数
我创建主类,然后从主类创建线程类的实例。线程类的构造函数传递了主线程的“this”指针。然后我可以从线程内的主类中运行函数 - 即我得到一个命令来执行从线程中运行主类中的函数的命令。我有互斥体等来防止竞争问题。
我是否以错误的方式处理这个问题 - 看起来线程类应该继承主类,或者另一种方法是不具有单独的线程类,而只是将它们作为主类的函数,但这会变得丑陋。
What is the best way of performing the following in C++. Whilst my current method works I'm not sure it's the best way to go:
1) I have a master class that has some function in it
2) I have a thread that takes some instructions on a socket and then runs one of the functions in the master class
3) There are a number of threads that access various functions in the master class
I create the master class and then create instances of the thread classes from the master. The constructor for the thread class gets passed the "this" pointer for the master. I can then run functions from the master class inside the threads - i.e. I get a command to do something which runs a function in the master class from the thread. I have mutex's etc to prevent race problems.
Am I going about this the wrong way - It kinda seems like the thread classes should inherit the master class or another approach would be to not have separate thread classes but just have them as functions of the master class but that gets ugly.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
对我来说听起来不错。在我的服务器中,它被称为“SCB”(ServerControlBlock),并提供对 IOCP 缓冲区/套接字池、记录器、状态/错误消息的 UI 访问以及所有处理程序线程需要共用的任何其他服务的访问。工作正常,我不认为这是一种黑客行为。
在创建使用 SCB 的线程池之前,我创建了 SCB(并确保在 ctor 中通过它访问的所有服务都已启动并准备好使用)——没有令人讨厌的单例内容。
平均值,
马丁
Sounds good to me. In my servers, it is called 'SCB' - ServerControlBlock - and provides access to services like the IOCPbuffer/socket pools, logger, UI access for status/error messages and anything else that needs to be common to all the handler threads. Works fine and I don't see it as a hack.
I create the SCB, (and ensure in the ctor that all services accessed through it are started and ready for use), before creating the thread pool that uses the SCB - no nasty singletonny stuff.
Rgds,
Martin
单独的线程类是很正常的,特别是如果它们具有特定的功能。我不会从主线程继承。
Separate thread classes is pretty normal, especially if they have specific functionality. I wouldn't inherit from the main thread.
将
this
指针传递给线程本身并不是坏事。你可以用它做什么。this
指针就像任何其他 POD-ish 数据类型一样。它只是一大块。然而,this
中的内容可能不仅仅是 POD,而且出于所有常见原因,将实际上的指针传递给其成员可能是危险的。每当您跨线程共享任何内容时,都会引入潜在的竞争条件和死锁。当然,解决这些冲突的基本方法是以互斥体、信号量等形式引入同步,但这可能会产生序列化应用程序的惊人效果。假设您有一个线程从套接字读取数据并将其存储到同步命令缓冲区,另一个线程从该命令缓冲区读取数据。两个线程使用相同的互斥体来保护缓冲区。一切都很好,对吧?
嗯,也许不是。如果您不太小心锁定缓冲区的方式,您的线程可能会被序列化。大概您为缓冲区插入和缓冲区删除代码创建了单独的线程,以便它们可以并行运行。但是如果你在每次插入时锁定缓冲区每次删除,则一次只能执行其中一个操作。只要您写入缓冲区,就无法从中读取,反之亦然。
您可以尝试微调锁,使它们尽可能简短,但只要您共享、同步数据,您就会有一定程度的序列化。
另一种方法是显式地将数据交给另一个线程,并尽可能多地删除数据共享。例如,您的套接字代码可能会在堆上创建某种
Command
对象(例如Command* cmd = new Command(. ..);
) 并将其传递给另一个线程。 (在 Windows 中执行此操作的一种方法是通过 QueueUserAPC机制)。有优点和缺点。两种方法的缺点。同步方法的优点是表面上更容易理解和实现,但潜在的缺点是如果弄乱了某些东西,调试起来会更加困难。切换方法可以使同步固有的许多问题变得不可能(从而实际上使其变得更简单),但在堆上分配内存需要时间。
Passing the
this
pointer to threads is not, in itself, bad. What you do with it can be.The
this
pointer is just like any other POD-ish data type. It's just a chunk of bits. The stuff that is inthis
might be more than PODs however, and passing what is in effect a pointer to it's members can be dangerous for all the usual reasons. Any time you share anything across threads, it introduces potential race conditions and deadlocks. The elementary means to resolve those conflicts is, of course, to introduce synchronization in the form of mutexes, semaphores, etc, but this can have the suprising effect of serializing your application.Say you have one thread reading data from a socket and storing it to a synchronized command buffer, and another thread which reads from that command buffer. Both threads use the same mutex, which protects the buffer. All is well, right?
Well, maybe not. Your threads could become serialized if you're not very careful with how you lock the buffer. Presumably you created separate threads for the buffer-insert and buffer-remove codes so that they could run in parallel. But if you lock the buffer with each insert & each remove, then only one of those operations can be executing at a time. As long as your writing to the buffer, you can't read from it and vice versa.
You can try to fine-tune the locks so that they are as brief as possible, but so long as you have shared, synchronized data, you will have some degree of serialization.
Another approach is to hand data off to another thread explicitly, and remove as much data sharing as possible. Instead of writing to and reading from a buffer as in the above, for example, your socket code might create some kind of
Command
object on the heap (egCommand* cmd = new Command(...);
) and pass that off to the other thread. (One way to do this in Windows is via the QueueUserAPC mechanism).There are pros & cons to both approaches. The synchronization method has the benefit of being somewhat simpler to understand and implement at the surface, but the potential drawback of being much more difficult to debug if you mess something up. The hand-off method can make many of the problems inherent with synchronization impossible (thereby actually making it simpler), but it takes time to allocate memory on the heap.