PDA

View Full Version : Lập trình đa tiểu trình với hàm CREATETHREAD



halo
26-04-2005, 10:19
Các bạn chỉ cho mình với: trong tại sao khi mình lập trình kiểu hàm thông thường thì gọi hàm CREATETHREAD() không có vấn đề gì nhưng khi mình chuyển đoạn hàm của mình sang kiểu hường đối tượng thì khi debug VC lại báo lỗi typecast gì đó
void CSocketMFC_ServerDlg::OnShow()
{
// TODO: Add your control notification handler code here

hSock1=SockSend.Detach();
SockSend.Attach(hSock1);
hSock2=SockReceive.Detach();
SockReceive.Attach(hSock2);
LPVOID lp=NULL;
//Tao hai tieu trinh send va recieve
h1=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Rec ieveThread,(LPVOID)hSock2,0,NULL);
......
}
Mình bó tay rồi mà gần hết hạn nộp project rùi, nếu bạn nào biết cách khắc phục hoặc hiểu nguyên nhân vấn đề thì chỉ giúp mình, với lẹ lẹ giùm!!!

htbn_hoang
26-04-2005, 14:26
Để tạo tiểu trình mới thì các tiểu trình (các hàm được sử dụng trong CreateThread) phải được khai báo toàn cục,tức là hàm đó không được phép nằm trong bất cứ lớp nào. Bạn nên định nghĩa các hàm loại này trong một tập tin, sau đó include chúng vào nơi mà bạn muốn dùng.

halo
26-04-2005, 22:53
ừ nhỉ, để mình thử theo ý kiến của bạn, anyway thanks

CodeForBeer
27-04-2005, 11:17
Khong ha(?n vay dau htbn_hoang, ba.n va~n co the? du`ng 1 static member ThisPointer (set no bang instance cua class do'), roi ban tao cai ReceiveThread as a static member function as well.
Anyway, ban Halo, loi cua? ban co' le~ la trong cai ReceiveThread ban o co' typecasting cai hSock2 phai ko (vi' du. HANDLE * hSock = (HANDLE *)hSock2 , minh ko biet datatype cua hSock2 la` gi` nen chi cho vi' du vay thoi) ? Ban nen noi ro~ la` khi debug ban da~ bi. error o? line nao`...v..v...

halo
27-04-2005, 23:41
mình bị lỗi ngay dòng gọi :
h1=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Rec ieveThread,(LPVOID)hSock2,0,NULL);
nó báo lỗi thế này:
error C2440: 'type cast' : cannot convert from '' to 'unsigned long (__stdcall *)(void *)'

mà lạ lắm nếu không để hàm RecieveThread thành 1 phương thức thì không bị
lỗi như vậy
hàm RecieveThread của mình như sau:
void CSocketMFC_ServerDlg::RecieveThread(LPVOID lp)
{
char sMgs[4096];
int nMsgLen;
CSocket Recieve;
Recieve.Attach((SOCKET)lp);
do
{
Recieve.Receive(&nMsgLen,sizeof(nMsgLen));
Recieve.Receive(sMgs,nMsgLen);
sMgs[nMsgLen]=0;
m_Recieve=sMgs;
UpdateData(FALSE);

} while(strcmp(sMgs,"exit")!=0);
h1=NULL;
ExitChat();

}
mà nếu không để thành một phương thức thì lại không truyền các giá trị khác của đối tượng vào Thread function được, kết quả là mình đang rất bí.

hSock2 nó chứa handle_socket của SockReceive:
CSocket SockReceive;
SOCKET hSock2;

CodeForBeer bạn có thể nói rõ hơn một chút được khg?

CodeForBeer
28-04-2005, 13:49
Giong nhu htbn_hoang va minh da noi qua, ReceiveThread phai la global function/static member function nen ban da bi loi nhu vay vi ReceiveThread cua ban la member func. only cua CSocket...class va trong do, ban cung muon goi nhung member functions khac cua CSocket - hoac update UI..v..v, bay gio ban co' 2 cach de giai quyet van de...
1. La dung cach cua htbn_hoang, ReceiveThread se la global function (ie, dung co de no lam member func. cua CSocket, ma declare no rieng la 1 global function)...nhung ban phai pass nguyen object cua class qua (ie, this pointer thay vi hSock2) roi typecasting no lai dung CSocket...datatype...cai nay thi Microsoft khuyen ko nen lam, nhung ma no van work so far...ban cung co the dung cach khac la store cai this pointer cua class CSocket as global cookie... dung Global interface pointer table (GIT). Nhung methods ban co the dung la: CoCreateInstance(CLSID_StdGlobalInterfaceTable,NUL L,CLSCTX_INPROC_SERVER)RegisterInterfaceInGlobal(. .), GetInterfaceFromGlobal va sau khi dung sau thi free no dung RevokeInterfaceFromGlobal(..)...
Cach nay thi dc hoan nghenh nhieu hon...nhung neu dung quen thi rat de...con moi dau thi chac ban se bo ngo~ ko biet cach passing input parameters nhu the nao...

2. Cach thu 2 thi nhu minh da noi them, la` dung static member variable This pointer va cai ReceiveThread se la static member function...thi ban co the initialize cai static member This pointer o trong cai default/derived constructor...roi trong cai ReceiveThread ban co the dung no de goi nhu~ng member function khac'...Dieu nen luu y la ban chi co the goi static members/methods only.

Qua cach ban lam, minh nghi chac ban muon viet 1 chuong trinh giong Chat (client/server)? Neu ban dung multithreads de handle client connections/requests thi cung nen can than viec access toi nhung shared memory (ie, global variables)...vi du co the dung Mutex, CriticalSection (neu the_to_be_called_method o chay lau qua'), hoac Semaphor...v..v...

halo
15-05-2005, 08:23
hu hu hu, các cao thủ cứu bồ giùm đi mình làm theo cách static func nhưng mà không thể nghĩ ra cách truyền dữ liệu của đối tượng vào trong static func
, mình đã thử tạo con trỏ kiểu lớp để truyền dữ liệu vào nhưng không được nó báo operator = không hợp lệ, không biết phải làm sao đây chắc tiêu quá

QuyKiemSau
25-05-2005, 17:45
Các bác a ! em làm bài tập về phần này cũng mắc chứng bệnh tương tự như anh bạn HaLo nhà ta ! . Nếu em tạo tiểu trình mà hàm tạo tiểu trình được định nghĩa nằm ngoài lớp thì hoàn toàn không có vấn đề gì và chương trình vẫn chạy tốt còn khi mang hàm khai báo và định nghĩa vô trong lớp nào đó thì trình biên dịch báo lỗi như HaLo thông báo . Vậy bây giờ có bác nào có cao kiến gì để tiểu trình khai báo và định nghĩa trong lớp mà không xảy ra lỗi gì cả . Xin các bác chỉ giáo !!! Cám ơn !

QuyKiemSau
25-05-2005, 22:44
/* Em không hiểu vì sao khi tao tiểu trình không có lỗi đến khi vào hàm tiểu trình sinh ra lỗi tai dòng (+++) . Chú ý : Vùng găng tạo ra an toàn không có vấn đề gì . Các bác làm ơn xem và sửa lỗi nhanh giúp em với . Em đang rất cần */
//***** Tao tieu trinh nhan du lieu tu cac Client *****
DWORD WINAPI ReceiveThread(LPVOID lParam)
{
unsigned int ret =0 ;
unsigned __int8 Index ;
CServerDlg c_ServerDlg ;
char _szBuffer_[999] ;

CMySocket *c_Socket = (CMySocket*)lParam;
//***** Lay dia chi ma Socket da ket noi *****
struct sockaddr_in SockAddr ;
int iSize = sizeof(SockAddr);
char szIpName[20] , temp[10];

//***** Lay thong tin ve dia chi IP cua Socket *****
c_Socket->GetPeerName((struct sockaddr *)&SockAddr ,&iSize);

//***** Lay dia chi IP cua Client *****
strcpy(szIpName,inet_ntoa(SockAddr.sin_addr));

//***** Tim IP cua Client thu may trong mang *****
Index = c_ServerDlg.TestIPAddr(szIpName) ;
itoa(Index , temp , 10) ;

//***** Loi tao *****
if (c_Socket == NULL )
{
TerminateThread(hThread[Index] , 1) ;
return FALSE;
}
AfxMessageBox(szIpName) ;// Xuất địa chỉ IP hoàn toàn đúng

while(TRUE)
{
//***** vao mien gang *****
EnterCriticalSection(&CS);
ret = c_Socket->Receive(_szBuffer_,MaxBuffer ,0);//Lỗi xảy ra ở đây (+++)
if (ret == 0 || ret == SOCKET_ERROR) // Client da dong ket noi
{
LeaveCriticalSection(&CS);
TerminateThread(hThread[Index] , 1) ;
return TRUE ; // Ket noi da dong
}
//***** Nhan du lieu thanh cong *****
_szBuffer_[ret] = NULL ;
if (_szBuffer_[0]!= NULL)//Hien thi thong diep
{
strcat(_szBuffer_ , "\n\n ===== La thong diep tu may : ");
strcat(_szBuffer_ , temp );
strcat(_szBuffer_ , " ===== ");
AfxMessageBox(_szBuffer_);

}
_szBuffer_[0] = NULL ;
//***** Roi khoi mien gang nhuong quyen cho tieu trinh # Sdung vung gang *****
LeaveCriticalSection(&CS);
}
return TRUE ;
}

ironus
25-05-2005, 23:46
ret = c_Socket->Receive(_szBuffer_,MaxBuffer ,0);//Lỗi xảy ra ở đây (+++)


MaxBuffer khai báo ở đâu nhỉ?
Bạn thử sửa nhanh:
ret = c_Socket->Receive(_szBuffer_, sizeof(_szBuffer_) - 1, 0);
//
// int MaxBuffer = sizeof(_szBuffer_) - 1;
//

QuyKiemSau
26-05-2005, 10:39
Ch­ương trình của em đã chạy rồi mà . Khi chạy nó mới báo lỗi . MaxBuffer em khai báo ở trên rồi = 999 . Các huynh xem giúp em tiếp với .

halo
29-05-2005, 08:30
không hiểu bác QuyKiemSau có phải dân tự nhiên không, tốt nhất bác nên chuyển qua làm kiểu thầy chỉ đi ! làm hàm Run của lớp CWinThread đó chứ đừng làm kiểu này gặp rất nhiều khó khăn khi truyền dữ liệu, tui đã từ bỏ kiểu này rùi!

mo dung phuc
05-06-2005, 18:45
mình bị lỗi ngay dòng gọi :
h1=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Rec ieveThread,(LPVOID)hSock2,0,NULL);
nó báo lỗi thế này:
error C2440: 'type cast' : cannot convert from '' to 'unsigned long (__stdcall *)(void *)'

mà lạ lắm nếu không để hàm RecieveThread thành 1 phương thức thì không bị
lỗi như vậy
hàm RecieveThread của mình như sau:
void CSocketMFC_ServerDlg::RecieveThread(LPVOID lp)
{
char sMgs[4096];
int nMsgLen;
CSocket Recieve;
Recieve.Attach((SOCKET)lp);
do
{
Recieve.Receive(&nMsgLen,sizeof(nMsgLen));
Recieve.Receive(sMgs,nMsgLen);
sMgs[nMsgLen]=0;
m_Recieve=sMgs;
UpdateData(FALSE);

} while(strcmp(sMgs,"exit")!=0);
h1=NULL;
ExitChat();

}
mà nếu không để thành một phương thức thì lại không truyền các giá trị khác của đối tượng vào Thread function được, kết quả là mình đang rất bí.

hSock2 nó chứa handle_socket của SockReceive:
CSocket SockReceive;
SOCKET hSock2;

CodeForBeer bạn có thể nói rõ hơn một chút được khg?

hình như là sai phần con trỏ, hSock2 là biến thường còn bạn phải truyền cho
hàm 1 con trỏ-> có lẽ nên thêm &
cái này mình không chắc lắm, bạn nên thử xem

evodanh
06-06-2005, 09:12
hSock2 là kiểu HANDLE, tức là một con trỏ, chứ không phải biến thường đâu!