Рейтинг:
9
User 13204940
Исправлено использование std::thread вместо этого. Гораздо аккуратнее, современнее и как-то решает этот вопрос. Не совсем уверен, как, но это делает свою работу.
struct ThreadData
{
PlayerConnection* instance;
SOCKET& socket;
};
ThreadData td = { this, socket };
std::thread t(receive, td);
t.join();
void receive(ThreadData data)
{
PlayerConnection* _this = data.instance;
SOCKET& socket = data.socket;
...
}
[no name]
Какой же ты жалкий ребенок. Это решило мою проблему, вы не в том положении, чтобы ее преуменьшать.
Рейтинг:
20
Rick York
То, что я обычно делаю в этой ситуации, как упоминал Ричард. Я использую статический метод интерфейса потока в качестве процедуры потока. A создайте другой нестатический метод, который создает поток и передает его в качестве аргумента. Затем он вызывает другой нестатический метод, который выполняет фактическую работу. Вот краткий пример с соответствующими битами :
class CMyObject
{
int ThreadMethod(); // do the work of the thread in this
static int ThreadProcedure( pvoid * p )
{
CMyObject * pthis = (CMyObject *)p;
return pthis->ThreadMethod();
}
void StartWorkThread()
{
// probably have to do some casting here to compile
BeginThread( ThreadProcedure, this ); // change this to create your thread
}
};
Иногда метод thread нуждается в некоторых дополнительных аргументах, поэтому я создаю небольшой класс или структуру для хранения аргументов вместе с указателем this, так как вы можете передать только одну вещь процедуре thread. Вот вам пример этого :
typedef struct
{
int arg1;
double arg2;
CSomethingElse * pse;
CMyObject * pthis;
} ThreadData;
int CMyObject::ThreadMethod( ThreadData *ptd )
{
// this was changed to accept the data argument
ThreadData td;
memcpy( &td, ptd, sizeof( ThreadData ) ); // make a copy
// and so on....
}
void CMyObject::StartWorkThread()
{
ThreadData td;
td.arg1 = 42;
td.arg2 = 3.1416;
td.pse = nullptr;
td.pthis = this;
BeginThread( ThreadProcedure, &td ); // change this to create your thread
}
int CMyObject::ThreadProcedure( pvoid *p )
{
ThreadData * ptd = (ThreadData *)p;
return ptd->pthis->ThreadMethod( ptd );
}
Вы также можете передать данные потока в ThreadMethod. Копия создается потому, что данные потока будут недействительны при возврате StartWorkThread.
[no name]
Вы это проверяли?
структура typedef
{
PlayerConnection* экземпляр;
Розетка& розетка;
} ThreadData;
void PlayerConnection::init(SOCKET& socket)
{
это->socket = сокет;
Данные ThreadData;
data.instance = это;
данных.гнездо = гнездо;
CreateThread(receive_thread, (LPVOID)данные);
}
Ошибка на receive_thread: argument of type "unsigned int (*)(ThreadData data)" is incompatible with parameter of type "LPSECURITY_ATTRIBUTES"
Ошибка в данных ThreadData: the default constructor of "ThreadData" cannot be referenced -- it is a deleted function
Ошибка в данных (LPVOID): no suitable conversion function from "ThreadData" to "LPVOID" exists
Даже если я изменю его на ThreadData* data, Too few arguments in function call
для CreateThread.
Rick York
Нет, я не проверял это, потому что я делаю это все время. Это работает. Вы читали комментарий там? Он говорит: "вероятно, придется сделать здесь какое-то литье, чтобы скомпилировать." У меня есть небольшая функция, которая упрощает этот материал для меня, что является общим для тех, кто много работает с потоками.
Если вы собираетесь передать данные, то это должно быть сделано с помощью указателя, так что это означает, что вам нужен оператор &, чтобы получить его адрес. Кроме того, дайте вызов CreateThread соответствующие аргументы, и вы должны быть почти там. Ошибка, которую я допустил, заключалась в том, что моя функция называется BeginThread, и я должен был использовать ее. Он имеет дело с атрибутами безопасности и размером стека. Я обновлю свой пост, чтобы использовать его.
[no name]
BeginThread не определен. Посмотрите на исходный пост, я обновил его до своего самого последнего кода.
Rick York
Вы, очевидно, не читали мой ответ. Это последний раз, когда я так трачу свое время.
[no name]
Вдобавок ко всему этому беспорядку я даже не могу использовать файл .h сейчас, потому что мне нужно объявить ThreadData в PlayerConnection.h, но он содержит член типа PlayerConnection*. Если я перемещаю ThreadData в другой файл, возникает циклическая зависимость, потому что он нуждается в playerconnection, но для этого требуется threaddata.h.
0x01AA
Мое мнение: прежде чем вы попробуете использовать потоки, вы должны быть в безопасности с основами. Средства, среди прочего, как предотвратить циклические зависимости....
[no name]
Я собираюсь обновить вопрос с помощью кода, который у меня сейчас есть. Это заставило меня чувствовать себя таким опустошенным и пресыщенным. Я не знаю никакого способа справиться с циклическими зависимостями, кроме как предотвратить их в первую очередь.
Jochen Arndt
Возразил один голос с 5 потому что это ответ:
Функция потока должен будьте статичны, и передача указателя на класс позволяет получить доступ к членам класса, который включает вызов нестатической версии функции потока.
Лучший метод, чем расширенный пример, заключается в том, чтобы по-прежнему передавать указатель на экземпляр класса и реализовывать дополнительные параметры как (обычно частные) члены класса, а не передавать структуру. Затем эти члены могут быть доступны с помощью нестатической функции потока или с помощью указателя класса в статической функции.
Rick York
Я иногда делаю это, но я не решаюсь добавлять членов в класс только для этой цели. Я думаю, что это сводится к вопросу предпочтения в этом вопросе.
Спасибо за голосование.