MFC中CAsyncSocket及其派生类对象跨线程使用方法

存在的现象

在MFC中用多线程方法开发WinSocket通讯程序时,如果你的的是API方式,自然没有以下说的问题。但如果当你使用CAsyncSocket及其派生类(CSocket或是你自己的写的)来开发的话,会发现在不同线程中使用CAsyncSocket及其派生类对象时,会出现程序崩溃。这里所说的跨线程,是指该对象在一个线程中调用Create/Close/Attach/Detach函数,然后在另外一个线程中调用其他成员函数如Receive/ReceiveFrom/Send/SendTo等。下面是一个典型的导致崩溃的例子程序(片断):

CAsyncSocket async_socket;

UINT ThreadProc(LPVOID) //出错:1

{

TRACE("======== ThreadDeattch出错:1 ========/n");

async_socket.Close (); //错误发生在这个调用上:要进行关闭async_socket对象.

return 0;

}

void CTsAsncSocketDlg::OnBnClickedButtonCreate() //出错:1

{

async_socket.Create(0);//async_socket对象在主线程中被建立

::AfxBeginThread(ThreadProc,0,0,0,0,0); //async_socket对象在主线程中被传递到另外的线程:ThreadProc

}

要想知道错误的原因,可以跟进去分析。这样说起来又太繁琐了,网上有不少类似的文章,问题的关键是不要在不同线程中进行Create/Close调用。

首先,当你的程序有问题的时候,怎样来判断是因为这个问题?这是关键一步。调试/断点/观测等有很多手段,VC++的IDE在个这个方面是非常出色的。这里还有个简单的方法。比如有如下代码:

class CSocketP3PServer : public CAsyncSocket

{

public:

CSocketP3PServer ();

~ CSocketP3PServer ();

public:

.......... //others

#if _DEBUG

private:

DWORD m_sockCurrentThreadId;

#endif //_DEUBG

};

void CSocketP3PServer::CSocketP3PServer()

{

#if _DEBUG

m_sockCurrentThreadId = ::GetCurrentThreadId();

#endif //_DEBUG

}

CSocketP3PServer::~CSocketP3PServer()

{

#if _DEBUG

if(m_sockCurrentThreadId != ::GetCurrentThreadId())

{

//如果程序走到这里来了,那么应该是跨线程使用造成的问题

TRACE("======= CSocketP3PServer 对象(Address:%d)在不同线程调用了 ========/n",this);

}

#endif //_DEBUG

}

知道了问题所在,解决的办法就很好说了,网上也有很多相关的介绍文章。这里是把这些解决方法整理一下。

解决的思路主要有2条:

1:避免这个问题的出现,也就是说避免在跨线程中使用CAsyncSocket及其派生类对象。

关于这点有很多的招数,比如说可以 A线程专门作收发工作,而其它线程把相关的数据通过数据共享或是其它手段在彼此之间传递。这个就是一个<读者-作者>之间的关系。还有其它的办法,总之,就是要把socket对象整个生命期都在单一的线程上。

2:实在是没有办法避免不在跨线程中使用CAsyncSocket及其派生类对象的,可以通过在线程之间传递SOCKET <变量>来实现,这里给个例子,代码如下:

UINT ThreadDeattchMe(LPVOID pv) //正确的在跨线程使用as_socket,这里是工作线程A

{

TRACE("======== ThreadDeattch 正确的在跨线程使用SOCKET ========/n");

as_socket.Attach((SOCKET)pv); //<---------- 注意这里传递的是 SOCKET <变量>

as_socket.Close ();

return 0;

}

void CTsAsncSocketDlg::OnBnClickedButtonCreate()//正确的在跨线程使用SOCKET,这里是主线程

{

as_socket.Create(0);

AfxBeginThread(ThreadDeattchMe,(LPVOID)as_socket.Detach(),0,0,0,0);//<---------- 注意这里传递的是 SOCKET <变量>

}

时间: 2024-10-06 01:15:07

MFC中CAsyncSocket及其派生类对象跨线程使用方法的相关文章

基类中定义的虚函数在派生类中重新定义时,其函数原型,包括返回类型、函数名、参数个数、参数类型及参数的先后顺序,都必须与基类中的原型完全相同 but------&gt; 可以返回派生类对象的引用或指针

您查询的关键词是:c++primer习题15.25 以下是该网页在北京时间 2016年07月15日 02:57:08 的快照: 如果打开速度慢,可以尝试快速版:如果想更新或删除快照,可以投诉快照. 百度和网页 http://bbs.csdn.net/topics/380238133 的作者无关,不对其内容负责.百度快照谨为网络故障时之索引,不代表被搜索网站的即时页面. 首页 精选版块 移动开发 iOS Android Qt WP 云计算 IaaS Pass/SaaS 分布式计算/Hadoop J

多继承(虚继承)派生类对象内存结构

在这里谈一下虚继承.前面写过派生类对象的内存结构,都是基于VS2010编译器的,不同的编译器对于继承的处理不同,但本质都是一样的. 虚继承是解决共享基类问题的.例如在菱形继承中 如果不使用虚继承,基类A在D中会有两个,这不仅浪费内存,还会造成歧义.使用虚继承就可以解决基类共享的问题. 要想在派生类中共享基类(例如在D对象中只有一个A对象,这时候D对象中的B对象和C对象都可以查找到A,而不是在B对象和C对象中各含有一个A对象). 先看下面一个例子: #include<iostream> usin

C++:基类与派生类对象之间的赋值兼容关系

4.5 基类与派生类对象之间的赋值兼容关系 在一定条件下,不同类型的数据之间可以进行类型转换,例如可以将整型数据赋给双精度型变量. 在赋值之前,先把整型数据转换为双精度型数据,然后再把它双精度型变量.这种不同类型之间的自动转换,称为赋值兼容.在基类和派生类对象之间也存在有赋值兼容关系,基类和派生类对象之间的赋值兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来代替.因为,通过公有继承,除了构造函数和析构函数外,派生类保留了基类其他的所有的成员.那么,派生类就具有基类的全部功能,凡

面向对象--多继承&amp;派生类对象内存布局分析&amp;各基类指针所指向的位置分析

背景 原文链接:ordeder  http://blog.csdn.net/ordeder/article/details/25477363 关于非虚函数的成员函数的调用机制,可以参考: http://blog.csdn.net/yuanyirui/article/details/4594805 成员函数的调用涉及到面向对象语言的反射机制. 虚函数表机制可以查看下面这个blog: http://blog.csdn.net/haoel/article/details/1948051 总结为: 其一

C++基类指针指向的派生类对象内存的释放

C++由于基类指针可以指向不同的派生类对象,因此当赋予基类指针不同的地址时,要注意之前的派生类对象的内存释放. int main(){ Parent* ptr = new Child1; Child2 myChild2; Child3 myChild3; ptr->show(); delete ptr; //位置1 ptr = &myChild2; ptr->show(); delete ptr; //位置2 ptr = &myChild3; ptr->show(); d

C++虚函数的陷阱--派生类对象的基类函数调用基类虚函数出错

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">最近写程序的时候发现,派生类对象的基类函数如果调用基类虚函数,则它将调用的是派生类的对应函数,而不是我想调用的基类的对应函数.</span> 下面用一个例子来说明: //基类 class Base { public: void funA(); virtual void fun

C++ 基类、派生类对象指针的声明与使用

1.类指针.对象指针 class x{ //- public: voidshow(); }; main() { x x1,*ptr1;           //定义类x的对象x1和类x的指针ptr1 x x2,*ptr2;           //定义类x的对象x2和类x的指针ptr2 x*ptr3;                 //定义类x的指针ptr3 //- ptr1 =&x1;           //将指针ptr1指向x1对象 ptr2 =&x2;           //将

为什么基类指针和引用可以指向派生类对象,但是反过来不行?

为什么基类指针和引用可以指向派生类对象,但是反过来不行? 基类指针和引用 BaseClass *pbase = NULL; DerivedClass dclass; pbase = & dclass; 基类指针和引用可以指向派生类对象,但是无法使用不存在于基类只存在于派生类的元素.(所以我们需要虚函数和纯虚函数) 原因是这样的: 在内存中,一个基类类型的指针是覆盖N个单位长度的内存空间. 当其指向派生类的时候,由于派生类元素在内存中堆放是:前N个是基类的元素,N之后的是派生类的元素. 于是基类的

【C++】派生类对象初始化基类的引用

//派生类对象初始化基类的引用 //引用是别名,但这个别名只能包含派生类对象中的由基类继承来的隐藏对象 #include <iostream> using namespace std; class B { public: B() { cout<<"B"<<endl; } void fun() { cout<<"B::fun()"<<endl; } private: int x; }; class D : p