C++ 在c+中后台运行线程+;11
我有一个带有connect_to方法的类,我在其中启动了一个线程,在调用它并加入它之后,我希望线程在后台运行,程序执行将继续,但它挂起在我的C++ 在c+中后台运行线程+;11,c++,multithreading,C++,Multithreading,我有一个带有connect_to方法的类,我在其中启动了一个线程,在调用它并加入它之后,我希望线程在后台运行,程序执行将继续,但它挂起在我的connect_to方法中,直到线程执行停止。我记得我曾经在C#中处理线程,一旦我启动它们,它们就在后台运行 #ifndef _TCP_CLIENT_H_ #define _TCP_CLIENT_H_ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif void connectio
connect_to
方法中,直到线程执行停止。我记得我曾经在C#中处理线程,一旦我启动它们,它们就在后台运行
#ifndef _TCP_CLIENT_H_
#define _TCP_CLIENT_H_
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
void connection_thread(void *user);
class TCPClient
{
public:
SOCKET m_ConnectSocket = INVALID_SOCKET;
char m_recvbuf[BUFFER_LENGTH];
int m_recvbuflen = BUFFER_LENGTH;
struct addrinfo* m_result = NULL, *m_ptr = NULL, m_hints;
vector<PacketInfo*> m_packet_list;
PacketInfo* m_packet_data = new PacketInfo();
thread* m_conn_thread;
int state = 0;
char* ip_address;
unsigned int port = 0;
TCPClient() {}
~TCPClient() {
delete m_packet_data;
}
int Init_Sockets() {
WSADATA wsaData;
int iResult;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 0;
}
return 1;
}
int Connect_to(char* ip, unsigned int port_number) {
port = port_number;
ip_address = ip;
//thread conn_thread(connection_thread, this);
thread conn_thread([=]() {connection_thread(this); return 1; });
conn_thread.join();
state = 0;
return 1;
}
}; // end TCPClient class
void connection_thread(void *user) {
TCPClient * self = static_cast<TCPClient*>(user);
// connecting code here... //
self->state = CONNECTED;
do {
iResult = recv(self->m_ConnectSocket, self->m_recvbuf, self->m_recvbuflen, 0);
if (iResult > 0) {
printf("Bytes received: %d\n", iResult);
}
else if (iResult == 0) {
printf("Connection closed\n");
self->state = DISCONNECTED;
}
else {
//printf("recv failed with error: %d\n", WSAGetLastError());
}
}
while (iResult > 0);
}
#endif
\ifndef\u TCP\u客户端\u H_
#定义\u TCP\u客户端\u H_
#如果NDEF WIN32_LEAN_和_MEAN
#定义WIN32_精益_和_平均值
#恩迪夫
无效连接螺纹(无效*用户);
类TCPClient
{
公众:
插座m_ConnectSocket=无效的_插座;
字符m_recvbuf[缓冲区长度];
int m_recvbuflen=缓冲区长度;
struct addrinfo*m_result=NULL,*m_ptr=NULL,m_提示;
向量m_包列表;
PacketInfo*m_packet_data=new PacketInfo();
螺纹*m_连接螺纹;
int state=0;
字符*ip_地址;
无符号整数端口=0;
TCPClient(){}
~TCPClient(){
删除m_数据包;
}
int Init_Sockets(){
WSADATA WSADATA;
国际结果;
iResult=WSAStartup(MAKEWORD(2,2)和wsaData);
如果(iResult!=0){
printf(“WSAStartup失败,错误:%d\n”,iResult);
返回0;
}
返回1;
}
int Connect_to(字符*ip,未签名的int端口号){
端口=端口号;
ip_地址=ip;
//螺纹连接螺纹(连接螺纹,本);
线程连接线程([=](){连接线程(this);返回1;});
连接螺纹。连接();
状态=0;
返回1;
}
}; // 结束TCPClient类
无效连接\u线程(无效*用户){
TCPClient*self=静态转换(用户);
//正在连接代码//
自->状态=已连接;
做{
iResult=recv(self->m_ConnectSocket,self->m_recvbuf,self->m_recvbuflen,0);
如果(iResult>0){
printf(“收到的字节数:%d\n”,iResult);
}
else if(iResult==0){
printf(“连接关闭\n”);
自->状态=断开连接;
}
否则{
//printf(“recv失败,错误:%d\n”,WSAGetLastError());
}
}
而(iResult>0);
}
#恩迪夫
线程按预期工作,并处于恒定循环中,直到连接关闭。知道我错过了什么吗
我有一个带有connect\u to方法的类,我正在其中启动一个线程,调用它并加入它之后,我希望线程在后台运行,程序执行将继续,但它挂起在connect\u to方法中,直到线程执行停止
这就是加入一个线程应该做的
如果您不想加入该线程,那么干脆不要加入。:)
不过,您可能至少应该在类析构函数中或以后的某个时间执行此操作,以便主线程不能在工作线程仍在执行时尝试结束。因为那将以眼泪结束
在我看来,这是一个完美的例子,说明了为什么我们不应该在不理解我们为什么这样做的情况下编写代码行。:)您对conn\u thread.join()的含义做了一个假设,这个假设是错误的:在这种情况下,首先要做的事情之一是阅读文档,以确保您的假设成立。理想情况下,您应该在编写代码之前阅读它,但没关系。它处于挂起状态,因为对
join()
的调用会导致当前线程暂停,直到连接线程完成,此时对join()
的调用将返回
conn_thread.join(); // Current thread will wait
// until conn_thread finishes.
您在评论中还提到,如果您不进行连接,则会调用中止。这是因为如果线程的析构函数所表示的线程仍然是可连接的,则它调用terminate()
由于线程对象是本地对象,因此在调用Connect\u to()
结束时,它将被销毁
那你怎么阻止它呢
detach()
方法线程
属于更大的上下文,这样它就不会被破坏detach()
不是一个好主意。由于您失去了对运行线程的所有引用,因此与它的通信变得很困难
我还注意到您的类TCPClient
thread* m_conn_thread;
这似乎没有被使用。如果将线程存储在此对象中,它将与该对象一样长(因此比函数更长)。很明显,由于线程访问对象的成员,因此对象的持续时间应该与线程的持续时间一样长 因此,我将进行以下更改:
// 1 Make the member a real variable not a pointer.
std::thread m_conn_thread;
// 2 Initialize this in the constructor.
TCPClient()
: m_conn_thread() // no thread created with this constructor.
{}
// 3 Create and assing a thread to this variable.
int Connect_to(char* ip, unsigned int port_number) {
// STUFF
m_conn_thread = std::move(std::thread([=]() {connection_thread(this); return 1; }));
// MORE STUFF
}
// Add a destructor that waits for the thread to join.
~TCPClient()
{
// As the thread is using members from this object
// We can not let this obect be destroyed until
// the thread finishes executing.
m_conn_thread.join();
// At this point the thread has finished.
// Destructor can now complete.
// Note: Without the join.
// This could potentially call terminate()
// as destroying the member m_conn_thread while the
// the thread is still running is bad.
}
不幸的是,如果我不加入它,我会得到一个错误框:调试错误!R6010-abort()已被调用。@Skrakle:这不是加入它的理由(其记录的目的实际上与您想要做的相反)。这就是为什么调用了
abort()
的原因。无论如何,原因可能是我在第三段中所说的…@LightnessRacesinOrbit有时,反复试验就能理解原因。根据个人的学习风格,他们可能必须通过编写代码来探索代码,以了解其行为,从而了解他们是否需要(或不需要)代码。如果最终结果都是一样的,这不一定是坏事:用户理解他们需要做什么以及为什么。@Javia1492:一切都很好,但仍然没有理由不在编程之前阅读文档,或者在对程序没有按预期工作感到困惑时不阅读文档。这不是“试错”;这是“尝试并寻求帮助”。@LightnessRacesinOrbit:是的,我同意。盲目地说“哦,它不工作”是不正确的。谢谢你的详细解释!当我意识到我初始化了第
// 1 Make the member a real variable not a pointer.
std::thread m_conn_thread;
// 2 Initialize this in the constructor.
TCPClient()
: m_conn_thread() // no thread created with this constructor.
{}
// 3 Create and assing a thread to this variable.
int Connect_to(char* ip, unsigned int port_number) {
// STUFF
m_conn_thread = std::move(std::thread([=]() {connection_thread(this); return 1; }));
// MORE STUFF
}
// Add a destructor that waits for the thread to join.
~TCPClient()
{
// As the thread is using members from this object
// We can not let this obect be destroyed until
// the thread finishes executing.
m_conn_thread.join();
// At this point the thread has finished.
// Destructor can now complete.
// Note: Without the join.
// This could potentially call terminate()
// as destroying the member m_conn_thread while the
// the thread is still running is bad.
}