Classes partagées entre deux threads, et erreur sur select()
Bonjour !
Alors voici la premiere classe qui est partagée:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
|
#ifndef SELECTOR_H
#define SELECTOR_H
#if defined __MINGW32__
#include <winsock2.h>
#elif defined __GNUC__
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#endif
#include <map>
#include <vector>
#include <iostream>
#include "SessionsCollection.h"
class ServerSocket;
class Selector
{
public:
static const int NO_ACTIVITY = 0;
/** Default constructor */
Selector(ServerSocket* ss, SessionsCollection* sc)
{
server = ss;
sessions = sc;
online = false;
_maxfd = 0;
};
/** Default destructor */
~Selector() {};
int Select()
{
int r = (online) ? ((_maxfd == 0) ? NO_ACTIVITY : select(_maxfd, &recvfs, NULL, NULL, NULL)) : -1;
return r;
}
bool Ready(int sock)
{
bool r = (FD_ISSET(sock, &recvfs) == 0) ? false : true;
std::cout << "ready? " << sock << ((r) ? "yes":"no")<<std::endl;
return r;
}
void Add(int sock)
{
FD_SET(sock, &recvfs);
_maxfd = sock+1;
std::cout << "Added " << sock << " to recvfs"<<std::endl;
}
void Delete(int sock)
{
todelete.push_back(sock);
}
void Mod(int oldsock, int newsock)
{
FD_CLR(oldsock, &recvfs);
_maxfd = 0;
FD_SET(newsock, &recvfs);
for(auto itr = sessions->AllSessions().begin(); itr != sessions->AllSessions().end(); ++itr)
{
if(itr->first > _maxfd)
{
_maxfd = itr->first;
}
}
}
void Flush()
{
int sock;
for(auto itr = todelete.begin(); itr != todelete.end(); ++itr)
{
sock = *itr;
FD_CLR(sock, &recvfs);
_maxfd = 0;
for(auto itr = sessions->AllSessions().begin(); itr != sessions->AllSessions().end(); ++itr)
{
if(itr->first > _maxfd)
{
_maxfd = itr->first;
}
}
sessions->DeleteSession(sock);
}
todelete.clear();
}
Session* operator[] (int sock)
{
return ((sessions->AllSessions().find(sock) != sessions->AllSessions().end()) ? sessions->AllSessions()[sock] : NULL);
}
inline ServerSocket* Server() { return server; }
void PutOnline(bool o) { online = o; }
private:
ServerSocket* server;
SessionsCollection* sessions;
std::vector<int> todelete;
fd_set recvfs;
int _maxfd;
bool online;
};
#endif // SELECTOR_H |
Voici la deuxieme:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
|
#ifndef SESSIONSF_H
#define SESSIONSF_H
#include <map>
#include <iostream>
#include "../Tools/Session.h"
class Selector;
class SessionsCollection
{
public:
/** Default constructor */
SessionsCollection()
{
};
/** Default destructor */
~SessionsCollection() {};
void CreateSession(const std::string& ip, const int sock, Selector* slt)
{
_sessions[sock] = new Session(ip, sock, slt);
std::cout << "we have now " << _sessions.size() << " clients"<<std::endl;
}
void DeleteSession(int sock)
{
delete _sessions[sock];
_sessions.erase(_sessions.find(sock));
}
inline map<int, Session*>& AllSessions() { return _sessions; }
inline const int Count() { return _sessions.size(); }
void Mod(int oldsock, int newsock)
{
Session* buf = _sessions[oldsock];
buf->newSock(newsock);
_sessions.erase(_sessions.find(oldsock));
_sessions[newsock] = buf;
}
Session* operator[] (int sock)
{
return ((_sessions.find(sock) != _sessions.end()) ? _sessions[sock] : NULL);
}
private:
std::map<int, Session*> _sessions;
};
#endif // SESSIONS_H |
Elles sont donc partagée entre le main(), qui accepte les connexions entrantes, et un thread qui sert exclusivement à la réception des données.
La premiere classe est utilisée pour les macros FD*, ainsi que la fonction select.
La deuxieme est une collections de mes sessions, et permet d'en ajouter/supprimer/modifier.
Ces deux classes sont protegée par un mutex, pour eviter les conflits:
Code:
1 2 3 4 5 6 7 8 9 10 11
| #ifndef SHARED_H_INCLUDED
#define SHARED_H_INCLUDED
#include <pthread.h>
static pthread_mutex_t SharedMutex = PTHREAD_MUTEX_INITIALIZER;
void LockSharedMutex();
void UnlockSharedMutex();
#endif // SHARED_H_INCLUDED |
Passons au boucles, voici la boucle dans le main, qui sert à accepter mes connexions:
Code:
1 2 3 4 5 6 7 8 9 10 11
| while(!shutdown)
{
Incoming = acceptor->Accept();
if(Incoming.Error == 0)
{
LockSharedMutex();
sessions->CreateSession(Incoming.IP, Incoming.Socket, selector);
selector->Add(Incoming.Socket);
UnlockSharedMutex();
}
} |
Ca marche bien, il y a des cout dans CreateSession() & Add(). Aucun probleme.
Dans le thread, j'ai ceci:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
while(!shutdown)
{
LockSharedMutex();
std::cout << "thread: locked mutex" << std::endl;
if(Selectr->Select() < 0 || Collection->Count() == 0)
{
int e = WSAGetLastError();
if (e != 0)
{
std::cout << "WSA Error: " << e << std::endl;
UnlockSharedMutex();
exit(0);
}
std::cout << "thread: UNLOCKED MUTEX !" << std::endl;
UnlockSharedMutex();
continue;
}
std::cout << "has activicty, loopin on clientz" << std::endl;
for(auto itr = Collection->AllSessions().begin(); itr != Collection->AllSessions().end(); ++itr)
{
Target = itr->second;
std::cout << "loop over client (sock=" << itr->first << " /// " << Target->GetSocket() << std::endl;
/* code très long :D */
}
Selectr->Flush();
UnlockSharedMutex();
std::cout << "thread: UNLOCKED MUTEX !" << std::endl;
} |
Voici un apercu du probleme :
http://img268.imageshack.us/img268/8708/mutexx.png
Le select ne marche donc pas juste apres l'ajout d'un socket dans le descripteur de fichiers.
Une idée ?
merci, nico.