Как бороться с несколькими параметрами разных типов в C ++ 98? - PullRequest
0 голосов
/ 19 сентября 2019

Для реализации класса потока (In C++98 и Windows.h).У меня есть что-то вроде этого:

Thread::Thread(_beginthreadex_proc_type fn)
{
    m_raw = fn;
    m_args = 0;
    m_handle = 0;
    m_id = 0;
}

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

void Thread::Join()
{
    m_handle = (HANDLE)_beginthreadex(0, 0, m_raw, (m_args ? m_args : 0), 0, 0);
    if (m_handle) WaitForSingleObject(m_handle, INFINITE);
}

Этот код также отлично работает с функциями, которые не принимают никаких параметров.Теперь мой вопрос о том, как я могу в C ++ 98 получить переменные параметры в моем конструкторе и сохранить их.И NO я не могу использовать современный c ++, если бы это было так, мне не нужна помощь.Так что, плз, не давайте мне решения, реализованные с c ++ 11 или выше.

Обновление

Теперь я пробую решение в стиле Java, в котором каждый поток является IRunnable, который имеет чистыйвиртуальная функция с именем Run.И поток - почти то, что это реализация с diff, который является абстрактным классом.Таким образом, я могу избежать параметров, потому что я не передаю функцию, вместо этого я пишу другой класс, который наследуется от Thread и реализует Run.Код выглядит так:

Интерфейс

struct IRunnable
{
    virtual void Run() = 0;
};

Класс потока

class Thread : public IRunnable
{
    HANDLE m_handle;
    DWORD  m_id;
    typedef unsigned (__stdcall *Function)(void*);
    _beginthreadex_proc_type m_raw;
    void* m_args;
public:
    Thread();
    ~Thread();
    Thread(_beginthreadex_proc_type, void*);
    Thread(_beginthreadex_proc_type);
    unsigned GetId();
    virtual void Run() = 0;
    void Join();
    unsigned int __stdcall call(void*);
};

Вызов только является оберткой для вызова члена функции Run

unsigned int __stdcall Thread::call(void* data)
{
    Run();
    return 0;
}

Моя проблема здесь:

void Thread::Join()
{
    m_handle = (HANDLE)_beginthreadex(0, 0, &this->call, 0, 0, 0);
    if (m_handle) WaitForSingleObject(m_handle, INFINITE);
}

Когда я компилирую в vs2019, код выше выдает следующую ошибку:

error C2276: '&': illegal operation on bound member function expression

error C2660: '_beginthreadex': function does not take 5 arguments

Ответы [ 2 ]

2 голосов
/ 20 сентября 2019

Для вашего отредактированного вопроса причина, по которой вы получаете ошибку компиляции, заключается в том, что вы пытаетесь отправить адрес функции-члену вашего объекта Thread.Вы не можете использовать указатели на функции-члены и использовать их, не удерживая при этом указатель на объект.Вместо этого вы должны создать глобальную функцию, которая принимает Thread * в качестве аргумента, отправить указатель на эту функцию и позволить ей вызывать ваш работоспособный объект.

unsigned thread_entry(void* thread_ptr)
{
    Thread* thread = (Thread*) thread_ptr;
    return thread->call();
}

void Thread::Join()
{
    m_handle = (HANDLE)_beginthreadex(0, 0, thread_entry, this, 0, 0);
    if (m_handle) WaitForSingleObject(m_handle, INFINITE);
}

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

0 голосов
/ 20 сентября 2019

Если вы посмотрите практически на любую библиотеку потоков, они очень редко поддерживают отправку нескольких аргументов;вы обычно отправляете указатель на что-то, и если вам нужно много вещей, вы создаете структуру, содержащую много вещей, и отправляете на нее указатель.

Однако, если вы действительно этого хотите, вы можете использовать функции C varargsвыполнять итерацию по всем переменным аргументам и выделять из них связанный список, или выделять их массив, или любую другую структуру данных, которую вы хотите.Затем отправьте указатель на эту функцию в вашу запись потока.Тем не менее, ваша функция будет по-прежнему принимать только один указатель.

В C нет простого способа создать va_list, то есть, как передаются переменные аргументы.Вы не можете просто отправить va_list, который у вас есть в вашем основном потоке, потому что эта память не будет активной к тому времени, когда она достигнет вашего нового потока.Также нет хорошего способа расширить список va_list для заполнения аргументов функции.

Кстати, я понимаю, что вы используете C ++, но в отношении C ++ 98 его поддержка varargs в основном такая же, как вС, поэтому я упоминаю С в своем ответе.

...