מצב מתוסבך...

MotiAd

New member
מצב מתוסבך...

היי חברה. יש לי צרה קטנטנה שאני מנסה נכון לעכשיו להבין מה המקור שלה. יש לי מחלקה שיוצרת CriticalSection (שניים כאלו) ויוצרת ת'רד שהפרמטר שלו הוא מצביע this למחלקה שמכילה בתוכה את האובייקטים של ה-CriticalSections הללו. ברגע שהקוד של ה-ת'רד מתבצע הכל פועל מעולה חוץ מהקטע שבו אני מתחיל לעבוד איתם. אני קורא לפונקציה EnterCri... ושולח לה כפרמטר את האובייקט המתאים. אבל מה? היא גורמת ליצירה של שגיאה בתוכנית של כתיבה למקום לא מורשה (הפונקציית API מנסה לכתוב למקום שגוי/לא מורשה). יש לכם מושג או כיוון מה יכולה להיות הבעייה? אני מבצע Initialize... כהלכה ובודק שהאובייקטים נוצרו ושגם הת'רד מקבל אותם נכון אבל שוב ושוב התקלה הזו מתרחשת. באף מקום אחר בתוכנית אני לא עושה שימוש באובייקטים האלו לפני שאני יוצר את הת'רד או אחרי. שלכם, מוטי.
 

gilad_no

New member
סינכרון

אני לא זוכר כ"כ MFC, אבל אני חושב שאתה צריך להשתמש בCLOCK בשביל האובייקטים של MFC. בכל אופן, נסה ליצור CRITICAL_SECTION בעצמך (לא עם המחלקה של MFC), לאתחל אותו ולהשתמש בו עם API נקי. כמו כן, תבדוק את ערכי השגיאות שמחזירות הפונקציות השונות (איתחול, כניסה למקטע קריטי וכו')
 

MotiAd

New member
או קיי, תודה...

אני לא עובד עם MFC אלא עם API של וינדוס נטו. כל העניין הוא שהפונקציה InitializeCriticalSection מתבצעת כהלכה ולא מחזירה שום שגיאה (0). ברגע שאני עושה שימוש בפונקציה EnterCriticalSection ומעביר לה כפרמטר את אותו משתנה שנוצר בפונקציה הראשית של המחלקה ע"י InitializeCriticalSection שם מתרחשת השגיאה והפונקציה לא יכולה להחזיר לי שום ערך, משום שכשאני עושה דיבג אז הוא מצביע לי על הפונקציה הזו ועל הפרמטרים שלה. כאילו הפונקציה הזו לא מצליחה לכתוב למשתנה שהעברתי לה. מוזר מאוד. אני קורא לפונקציה EnterCriticalSection מתוך ת'רד שאני יוצר בפונקציה הראשית של המחלקה.
 

MotiAd

New member
הנה הקוד...

זה הקוד של המחלקה שיוצרת את הת'רד: זה מה שנמצא בקובץ Sockets.h
DWORD WINAPI Reader(LPVOID lpParameter); DWORD WINAPI Sender(LPVOID lpParameter); class SocketServer{ private: WSADATA wsaData; SOCKET m_socket; SOCKET AcceptSocket; sockaddr_in service; string address; int port; queue<Message> MessagesOut; queue<Message> MessagesIn; CRITICAL_SECTION csQueueIn; CRITICAL_SECTION csQueueOut; friend DWORD WINAPI Reader(LPVOID lpParameter); friend DWORD WINAPI Sender(LPVOID lpParameter); public: SocketServer(string add="127.0.0.1", int po=56557); ~SocketServer(); const BYTE ReadByte(); const WORD ReadWord(); const DWORD ReadDWord(); const BYTE *ReadBytes(int &len); void SendByte(); void SendWord(); void SendDWord(); void SendBytes(); void PopMessage(); void PushMessage(Message &msg); };​
זה הקוד של הת'רדים שבמחלקה הזו:
#include "Sockets.h" DWORD WINAPI Reader(LPVOID lpParameter){ LPCRITICAL_SECTION lpCrit = &(((SocketClient *)lpParameter)->csQueueIn); SocketClient *sc = (SocketClient *)lpParameter; int bytesRecv = SOCKET_ERROR; char *recvbuf; char num[4]; long header; Message s; ofstream f("c:\\1234.txt"); for(;;){ while(bytesRecv == SOCKET_ERROR){ MessageBox(NULL, "1", NULL, MB_OK | MB_ICONINFORMATION); bytesRecv = recv(sc->m_socket, num, 4, 0); f<<bytesRecv<<endl; while(bytesRecv < 4){ if (bytesRecv <= 0 || bytesRecv == WSAECONNRESET){ return (DWORD)0; } bytesRecv += recv(sc->m_socket, num + bytesRecv, 4-bytesRecv, 0); } f<<(long)num[0]<<endl; f<<(long)num[1]<<endl; f<<(long)num[2]<<endl; f<<(long)num[3]<<endl; f<<(long)(num[0]<<24)<<endl; f<<(long)(num[1]<<16)<<endl; f<<(long)(num[2]<<8)<<endl; f<<(long)(num[0]<<24) + (long)(num[1]<<16) + (long)(num[2]<<8) + (long)(num[3])<<endl; header = (long)(num[0]<<24) + (long)(num[1]<<16) + (long)(num[2]<<8) + (long)(num[3]); f<<header<<endl; recvbuf = new char[header]; bytesRecv = recv(sc->m_socket, recvbuf, header, 0); f<<bytesRecv<<endl; MessageBox(NULL, "2", NULL, MB_OK | MB_ICONINFORMATION); if (bytesRecv <= 0 || bytesRecv == WSAECONNRESET){ return (DWORD)0; } while(bytesRecv < header){ bytesRecv += recv(sc->m_socket, recvbuf + bytesRecv, header - bytesRecv, 0); if(bytesRecv <= 0 || bytesRecv == WSAECONNRESET){ return (DWORD)0; } } MessageBox(NULL, "3", NULL, MB_OK | MB_ICONINFORMATION); f<<header<<endl; f.write(recvbuf, header); s.message = new char[header]; memcpy(s.message, recvbuf, header); delete [] recvbuf; MessageBox(NULL, "4", NULL, MB_OK | MB_ICONINFORMATION); EnterCriticalSection(lpCrit); sc->MessagesIn.push(s); LeaveCriticalSection(lpCrit); MessageBox(NULL, "5", NULL, MB_OK | MB_ICONINFORMATION); } Sleep(500); } return (DWORD)0; }​
זה הקוד של בנאי המחלקה שגם יוצר את הת'רד:
SocketServer::SocketServer(string add, int po):address(add), port(po){ // getting the winsock ver​
 

MotiAd

New member
אאוץ...

הקוד של הבנאי לא נכנס אז הנה הוא:
זה הקוד של המחלקה שיוצרת את הת'רד: זה מה שנמצא בקובץ Sockets.h
זה הקוד של בנאי המחלקה שגם יוצר את הת'רד:
SocketServer::SocketServer(string add, int po):address(add), port(po){ // getting the winsock ver and imp int iResult = WSAStartup(MAKEWORD(2,2), &wsaData); string error; ofstream f("c:\\12.txt"); // creating critical sections InitializeCriticalSection(&csQueueIn); InitializeCriticalSection(&csQueueOut); if (iResult != NO_ERROR){ error = "Error at WSAStartup() " + WSAGetLastError(); f<<error<<endl; throw exception(error.c_str()); } // saying that tcp/ip should be used m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Check for errors to ensure that the socket is a valid socket. if(m_socket == INVALID_SOCKET){ WSACleanup(); error = "Error at socket(): " + WSAGetLastError(); f<<error<<endl; throw exception(error.c_str()); } // initing the struct service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr(address.c_str()); service.sin_port = htons((u_short)port); // binding the socket if(bind( m_socket, (SOCKADDR*) &service, sizeof(service) ) == SOCKET_ERROR ) { closesocket(m_socket); error = "bind() failed. " + WSAGetLastError(); f<<error<<endl; throw exception(error.c_str()); } // listening if(listen(m_socket, 1) == SOCKET_ERROR){ error = "Error listening on socket. " + WSAGetLastError(); f<<error<<endl; throw exception(error.c_str()); } while(1){ AcceptSocket = (SOCKET)SOCKET_ERROR; while (AcceptSocket == SOCKET_ERROR){AcceptSocket = accept(m_socket, NULL, NULL);} m_socket = AcceptSocket; break; } CreateThread(NULL, 0, Reader, this, NULL, NULL); //send recv drill int bytesSent; int bytesRecv = SOCKET_ERROR; char sendbuf[32] = "Server: Sending Data."; char recvbuf[32] = ""; bytesRecv = recv(m_socket, recvbuf, 32, 0); f<<"Bytes Recv: "<<bytesRecv<<endl; f.write(recvbuf, bytesRecv); bytesSent = send( m_socket, sendbuf, strlen(sendbuf), 0 ); f<<"Bytes Sent: "<<bytesSent<<endl; }​
בעצם הבעייה מתרחשת בפונקציה Reader שהיא בת'רד. בחלק שבו מתחיל ה- EnterCriticalSection בשורה הזו נגרמת לי השגיאה ואני לא ממשיך משם.​
 

gilad_no

New member
תיקונים

לא עקבתי אחרי הכל, אבל תתחיל מתיקון קטן לדרך שבא אתה מפעיל את הTHREAD.
class CClass { protected: CRITICAL_SECTION m_CS; private: DWORD DynamicThread() { EnterCriticalSection(&m_CS); LeaveCriticalSection(&m_CS); return 0; } static DWORD WINAPI StaticThread(LPVOID pVoid) { return ((CClass*)pVoid)->DynamicThread(); } };​
לגבי המחלקה, בפרמטר של CREATETHREAD *תמיד* תעביר את THIS ותשתמש בו כדי להחזיר שליטה לפונקציה דינמית ואל תעבוד מתוך פונקציה סטטית.
 

MotiAd

New member
או קיי...

תודה רבה על התגובה המהירה ואני אקח את הפרטים לתשומת ליבי. אבל בכל מקרה אתה חושב שהבעייה נעוצה בזה? אני אבדוק את העניין בכל מקרה. תודה
 

MotiAd

New member
תודה רבה רבה גלעד!!!

הבעייה אכן נפתרה. המוזר הוא שאני לא מבין מה הייתה יכולה להיות הבעייה. הקוד לא השתנה בכלל חוץ מהעובדה שעכשיו אני ניגש למשתנים של המחלקה מתוכה ולא דרך מצביעים. כנראה שההרשאות היו שונות (ואת זה אני לא מבין - הרי ת'רד מקבל יכולת כתיבה מלאה על כל מרחב הזיכרון של האבא, לא?) אבל בכל מקרה תודה רבה רבה והבעייה נפתרה.
 

hatulflezet

New member
אולי

זה פשוט השורה הזו:
LPCRITICAL_SECTION lpCrit = &(((SocketClient *)lpParameter)->csQueueIn);​
אני מודה שלא ממש ירדתי לפרטי הקוד - אבל על פניו, אתה מעביר לlpCrit כתובת של מצביע - ולא מצביע לאובייקט - משמע ה& לפני הסוגרים מיותר - לא?
 

hatulflezet

New member
אתנ יכול לבדוק

את התאוריה שלי ע"י כך שתנסה לקרא ערכים מהמצביע שאתה מעביר לlpCrit לפני שאתה יוצר את lpCrit - אני מנבא שתקבל זבל...- אם זה אכן כך - הבעיה שלך לא קשורה בת'רד - אלא בזה שאתה מעביר מצביע שגוי.
 

MotiAd

New member
האובייקט csQueueIn...

הוא אובייקט לחלוטין. ולכן אני מעביר אותו כמצביעבאמצעות ה-&. למען האמת המצביעים בסדר גמור מה שעוד יותר מוזר.
 

hatulflezet

New member
וכשאתה עושה

משהו בסגנון:
LPCRITICAL_SECTION lpCrit = &(((SocketClient *)lpParameter)->csQueueIn); <member type> testMemver = lpCrit->m_member;​
testMember מחזיק בערך נכון? אם כן - אז כניראה שבאמת זה אכן קשור בנושא הת'רד...
 

אמיר ט

New member
אולי...

הפונקציית ת'רד שלך, היא קשורה למחלקה איכשהו ? יכול להיות שאותו משצנה שאתה מנסה לגשת אליו הוא private או protected ואז אין לך גישה אליו מפונקציות חיצוניות. אם זה המצב אתה צריך להגדיר את הפונקציית ת'רד שלך בקלאס בצורה הזאת :
friend DWORD WINAPI ThreadFunction(LPVOID lpvThreadParam);​
אצלי היה משהו דומה וזה עבד ככה כמו שצריך.
 

codec

New member
אכן, המשתנה הוא private

ולא תצליח לגשת אליו מבחוץ...
 
למעלה