LINUX.ORG.RU

moveToThread(this) лучше вообще не использовать...

SSZB
()
Ответ на: комментарий от Stil

Пишу сетевой чат. При подключении клиента к серверу нужно запустить новый поток обработки сигналов сокета клиента, но в Qt слоты запускаются в том потоке, в котором был создан сигнал, насколько я понял. И пока в решении этой проблемы пока помогло только moveToThread(this).

timocov
() автор топика
Ответ на: комментарий от timocov

наверняка в твоём чате пользователи общаются фильмами в хд формате, раз тебе надо на каждого пользователя по треду создавать?

что мешает обрабатывать всё в одном eventloop?

nanoolinux ★★★★
()
Ответ на: комментарий от timocov

ты что-то делаешь не так

как стартуют треды?

Stil ★★★★★
()
Ответ на: комментарий от timocov

в Qt слоты запускаются в том потоке, в котором был создан сигнал

Нет. Слот запускается в том потоке, к которому принадлежит объект в котором этот слот.

Когда ты создаешь QThread, он хоть и управляет отдельным потоком, тем не менее сам «принадлежит» основному потоку. Вот и получается, что все работает в одном потоке. Делая moveToThread(this) ты переносишь объект в поток, которым он сам и управляет. Теоретически так делать можно, по крайней мере в документации на Qt я не видел запрет этого. На практике так лучше не делать, а то мало ли оно что...

Короче, делаешь наследника от QObject, пихаешь в него что нужно, и делаешь myCoolObj->moveToThread(thread).

SSZB
()
Ответ на: комментарий от timocov

но в Qt слоты запускаются в том потоке, в котором был создан сигнал

Слоты запускаются в том потоке в котором создан содержащий их объект.

no-such-file ★★★★★
()
Ответ на: комментарий от SSZB

Сделал сейчас так. Получается, идет обработка в другом потоке, но теперь другая проблема: обработка происходит первого сигнала. Дальше хоть посылай, хоть отключайся - ничего не происходит.

QThread *thread = new QThread();
client_process *cl = new client_process(client);
cl->moveToThread(thread);
thread->start();
Правильно делаю? Коннекты описываю в конструкторе client_process.

timocov
() автор топика
Ответ на: комментарий от timocov

Похоже на правду.

другая проблема: обработка происходит первого сигнала

Слот возвращает управление? Другие сигналы не будут обрабатываться пока работает слот, а будут ставиться в очередь на обработку.

SSZB
()
Ответ на: комментарий от SSZB

Вот что в слоте. Писал просто проверки ради.

void client_process::some_func(){
	user *usr = (user*)sender();
	usr->get_socket()->write(usr->get_socket()->readAll());
}

timocov
() автор топика

тысработаешь с потоками неправильно

гугли статью от троллей. ключевое слово "you do it wrong". без шуток.

anonymous
()
Ответ на: комментарий от bhfq

Ты сам-то читал ту статью по ссылке?

Когда вам не нужен цикл обработки событий в вашем потоке, следует создать потомка QThread.
Если вам нужен цикл обработки событий и обработка сигналов и слотов внутри потока, наследоваться не стоит.

Ему нужен цикл обработки событий, эрго ему не нужно наследоваться, а нужно читать статью «you're doing it wrong».

О боги, на лоре сплошь одни хомячки, не способные не то, что думать самостоятельно, но и даже читать.

anonymous
()
Ответ на: комментарий от timocov

Попробуй заменить usr->get_socket()->write(usr->get_socket()->readAll()) на печать в консоле, посмотри, что получится.

SSZB
()
Ответ на: комментарий от anonymous

Как можно определить блокировку? Но тем не менее вся эта конструкция выполняет действие полностью.

timocov
() автор топика
Ответ на: комментарий от timocov

Лучше сразу научиться пользоваться воркерами. Один поток на обработку сетевых событий и пул потоков на запросы клиентов.

note173 ★★★★★
()
Ответ на: комментарий от note173

но в Qt слоты запускаются в том потоке, в котором был создан сигнал

В Qt (4.x + по крайней мере) по умолчанию слоты вызываются в контексте потока владеющего обьектом содержащим слот пруф.

Лучше сразу научиться пользоваться воркерами. Один поток на обработку сетевых событий и пул потоков на запросы клиентов.

Полностью поддерживаю, лучше сначала освоить тот же QtFuture, поиметь опыт работы с параллельными задачами, а потом уже разбираться как подобный функционал можно делать ручками, если желание(а точнее потребность) возникнет :)

P.S. если возникает необходимость в чем то типо moveToThread - то это в 90% проблема дизайна, а некоторые товарищи например считают что даже необходимость в локах признак плохого дизайна :) Разделять же сокеты между потоками это изначально бэд идея, проще иметь одного воркера с интерфейсом типа: postMessage; getQueuedMessages, а обработку пришедших сообщений передавать потокам.

batbko
()

Так что на счет того, что обрабатывается только первый сигнал?( Я уже переписал весь код с нуля. Сделал отдельно класс сервера, и класс работы с клиентом.

timocov
() автор топика
Ответ на: комментарий от timocov

Тебе же сказали, что у тебя блокируется на чтении (readAll) скорее всего.

anonymous
()
Ответ на: комментарий от solovey

client.h

#ifndef _CLIENT_H_	
#define _CLIENT_H_

#include <QMutex>
#include <QObject>
#include <QString>
#include <QMap>
#include <QtNetwork\QTcpSocket>
#include <server\data_base.h>

class client : public QObject{

	Q_OBJECT
		
public:
	client(QTcpSocket *socket_,QMutex *db_mutex_,QMutex *clients_mutex_,QMap<int,client*> *clients_);
	virtual ~client();

public slots:
	void disconnected();
	void send_message(QString message);

private slots:
	void sent();
	void primary_process();

signals:
	void auth_seccess(QString);
	void new_message(QString);
	void finished();

private:
	void authorization(QString login,QString password);
	void registration(QString login,QString password);
	bool auth;//needed?!
	QTcpSocket *socket;
	
	QString login;
	QString nick;
	
	const QMap<int,client*> *clients;
	QMutex *db_mutex;
	QMutex *clients_mutex;
};


#endif

client.cpp
#include <server\client.h>

client::client(QTcpSocket *socket_,QMutex *db_mutex_,QMutex *clients_mutex_,QMap<int,client*> *clients_)
			:auth(false),socket(socket_),db_mutex(db_mutex_),clients_mutex(clients_mutex_),clients(clients_){

	QObject::connect(socket,SIGNAL(disconnected()),this,SLOT(disconnected()));
	QObject::connect(socket,SIGNAL(readyRead()),this,SLOT(primary_process()));

}

client::~client(){
	if (auth) QObject::disconnect(socket,SIGNAL(readyRead()),this,SLOT(sent()));
	else QObject::disconnect(socket,SIGNAL(readyRead()),this,SLOT(primary_process()));

	QObject::disconnect(socket,SIGNAL(disconnected()),this,SLOT(disconnected()));

	socket->deleteLater();
	auth = false;
	emit finished();
}

void client::disconnected(){
	this->deleteLater();
}

void client::send_message(QString message){
	if (auth){
		socket->write(message.toUtf8().constData());
	}
}

void client::primary_process(){
	QString message = socket->readAll();
	if (message == "Please"){//request to database
		authorization("123","pass");
		return;
	}
	if (message == "Just"){//request to database
		registration("123","sss");
		return;
	}
	disconnected();
}

void client::authorization(QString login,QString password){
	QString real_password = "pass";//database.get_password(login);
	if (password != real_password){
		disconnected();
		return;
	}

	QObject::disconnect(socket,SIGNAL(readyRead()),this,SLOT(primary_process()));
	QObject::connect(socket,SIGNAL(readyRead()),this,SLOT(sent()));
	emit auth_seccess("Client:\nlogin - \'"+login+"\'\n was auth.\n");
	auth = true;
}

void client::registration(QString login,QString password){
	//if (data_base.reg_user(login,password));
	if (login != "223"){
		socket->write(QString("Reg is success. You may now auth on the server.").toUtf8().constData());
	}
	else {
		socket->write(QString("Sorry, but this login is busy.").toUtf8().constData());
		disconnected();	
	}
}

void client::sent(){
	QString message = socket->readAll();
	emit new_message(message);
}

server.h
#ifndef _SERVER_H_
#define _SERVER_H_

#include <QtNetwork\QTcpServer>
#include <QtNetwork\QTcpSocket>
#include <QMap>
#include <QString>
#include <QQueue>
#include <QMutex>
#include <server\client.h>



class server : public QObject {
	
	Q_OBJECT

public:
	server(int port = 0,QString db_name = "DataBase.dblite",QString server_name = "Fuckin server by timocov.");
	virtual ~server();

	void start();
	void stop();

	void set_port(int port);
	void set_name(QString name);


	bool started() const;
	int get_port() const;
	QString get_name() const;

public slots:
	void kick_all();
	void new_connection();
	void broadcasting(QString);
	
private slots:
	void delete_client();

signals:
	void disconnect_all();
	void stopped();
	void started();
	void broadcast(QString message);
	void new_connect();

private:
	int port;
	bool state;
	QString name;

	QTcpServer server_;

	QMap<int,client*> clients;
	
	QMutex db_mutex;
	QMutex clients_mutex;
};

#endif
server.cpp
#include <server\server.h>
#include <QThread>

server::server(int port_,QString db_name,QString server_name)
	:port(port_)/*,data_base(db_name)*/,name(server_name),state(false){}

server::~server(){
	stop();
	//db_close
	state = false;
}


void server::broadcasting(QString message){
	emit broadcast(message);		
}

void server::delete_client(){
	client *del = (client*)sender();
	int key = clients.key(del);
	clients.remove(key);
	QObject::disconnect(del,SIGNAL(destroyed()),this,SLOT(delete_client()));
}

void server::new_connection(){
	QTcpSocket *socket = server_.nextPendingConnection();
	
	client *_client = new client(socket,&db_mutex,&clients_mutex,&clients);
	int key = socket->socketDescriptor();

	clients_mutex.lock();
	clients[key] = _client;
	clients_mutex.unlock();

	QThread *thread = new QThread();

	QObject::connect(_client,SIGNAL(destroyed()),this,SLOT(delete_client()));
	QObject::connect(_client,SIGNAL(finished()),thread,SLOT(quit()));
	QObject::connect(_client,SIGNAL(new_message(QString)),this,SIGNAL(broadcast(QString)));
	QObject::connect(_client,SIGNAL(auth_seccess(QString)),this,SIGNAL(broadcast(QString)));

	QObject::connect(this,SIGNAL(broadcast(QString)),_client,SLOT(send_message(QString)));
	QObject::connect(this,SIGNAL(stopped()),_client,SLOT(disconnected()));
	QObject::connect(this,SIGNAL(disconnect_all()),_client,SLOT(disconnected()));

	_client->moveToThread(thread);

	thread->start();
	emit new_connect();
}

void server::start(){
	if (port == 0) return;
	if (state) return;

	if ( server_.listen(QHostAddress::Any,port) ){
		QObject::connect(&server_,SIGNAL(newConnection()),this,SLOT(new_connection()));
		state = true;
		emit started();
	}
}
void server::stop(){
	if (!state) return;
	kick_all();
	//emit disconnect_all();
	state = false;
	emit stopped();
}

void server::set_port(int port){
	this->port = port;
}

void server::set_name(QString name){
	this->name = name;
}

bool server::started() const{
	return state;
}

int server::get_port() const{
	return port;
}

QString server::get_name() const{
	return name;
}
void server::kick_all(){
	emit disconnect_all();
}

timocov
() автор топика
Ответ на: комментарий от timocov

client::~client(){
дисконнекты

Не нужно. При удалении объекта все коннекты убиваются.

QThread *thread = new QThread();

Ты нигде не удаляешь их, память утекает.

clients_mutex.lock();

Используешь при новом коннекте, но не при удалении.

Что касается твоей проблемы, то хз, сходу без запуска и отладки не нашел.

anonymous
()
Ответ на: комментарий от timocov

Еще раз настаиваю, чтобы ты прочитал это: moveToThread(this) (комментарий)

Предполагаю, что ошибка в

QThread *thread = new QThread();
...
_client->moveToThread(thread);
thread->start();

Согласно вышеприведенным ссылкам тебе надо отнаследовать QThread и в run () сделать exec ().

А так получается, что у тебя нет event loop'а.

З.Ы.: Я, конечно, сам плохо дружу с многопоточностью в Qt, но я делал, руководствуясь теми ссылками, и все получилось

solovey ★★
()
Ответ на: комментарий от solovey

Но зачем это делать еще раз? Или я вообще ничего понять не могу((
Вот что написано в qthread.cpp

void QThread::run()
{
    (void) exec();
}

timocov
() автор топика
Ответ на: комментарий от solovey

Согласно вышеприведенным ссылкам тебе надо отнаследовать QThread и в run () сделать exec ().

Не надо, с какой-то версии Qt (4.7 или 4.8) exec уже есть в run.
Да и если бы проблема была в этом, то у него вообще слото-сигналы не работали.

anonymous
()
Ответ на: комментарий от timocov

(void) exec();

Тогда, конечно, делать это еще раз бесполезно...

В таком случае не знаю, в чем может быть проблема.

solovey ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.