简体   繁体   中英

Using functor in pthread_create

What this code do:

Several commands executed to completion(if(current seconds == some seconds) stop). CommandProcessor(functor) run this commands. Pointer of this class I try to throw to pthread_create.

The question:

It is possible to use class object as callable?

command.h

#ifndef COMMAND_H
#define COMMAND_H

#include <iostream>
#include "commandprocessor.h"

class CommandProcessor;

using namespace std;

class Command
{
    static CommandProcessor *commandProcessor;
    time_t stopSeconds;

    public:
        Command(int _stopSeconds);
        static void setProcessor(CommandProcessor *_commandProcessor);
        void execute();
};

#endif // COMMAND_H

command.cpp

#include "command.h"

CommandProcessor* Command::commandProcessor = NULL;

Command::Command(int _stopSeconds)
{
    stopSeconds = _stopSeconds;
}

void Command::setProcessor(CommandProcessor *_commandProcessor)
{
    commandProcessor = _commandProcessor;
}

void Command::execute()
{
    time_t seconds;
    time_t now = time(NULL);
    seconds = localtime(&now)->tm_sec;
    cout << seconds << endl;
    if(seconds != stopSeconds)
        commandProcessor->addCommand(this);
}

commandprocessor.h

#ifndef COMMANDPROCESSOR_H
#define COMMANDPROCESSOR_H

#include <list>
#include "command.h"

using namespace std;

class Command;

class CommandProcessor
{
    list< Command* > commandsList;

    public:
        void addCommand(Command *_command);
        void operator()();
};

#endif // COMMANDPROCESSOR_H

commandprocessor.cpp

#include "commandprocessor.h"

void CommandProcessor::addCommand(Command *_command)
{
    commandsList.push_back(_command);
}

void CommandProcessor::operator()()
{
    while(commandsList.size() > 0)
    {
        Command *command = commandsList.front();
        commandsList.pop_front();
        command->execute();
    }
}

main.cpp

#include <iostream>
#include <pthread.h>
#include "commandprocessor.h"

#define MAX_THREADS 2

using namespace std;

int main(int argc, char **args)
{
    CommandProcessor *processor = new CommandProcessor();
    Command::setProcessor(processor);
    processor->addCommand(new Command(53));
    processor->addCommand(new Command(24));
    processor->addCommand(new Command(15));

    pthread_t threads[MAX_THREADS];
    for(int i=0; i < MAX_THREADS; i++)
    {
        pthread_create(&threads[i], NULL, processor(), NULL); // error: 'processor' cannot be used as a function
    }
    return 0;
}

DISCLAIMER : this is the kind of thing that you really shouldn't be doing in C++, as it includes messing around with void* . It needs to be used here because of the interaction with the C API. If you can, use std::thread from C++11 or boost::thread if you're using an older compiler.

To answer your question : yes, it is perfectly fine to make a class object as a callable (as a "function") once you implement operator() for it. You already did that, but the problem is the extra code needed to implement the interface between C++ and the C API for Pthreads.

The main reason why you're getting the " processor cannot be used as a function" error here is because processor is a CommandProcessor* and, as such, needs a dereference. However, even doing (*processor)() wouldn't help you, because pthread_create is defined as follows :

int pthread_create(phread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

This means that the function to be executed must return void* and take a void* . The documentation also states that the parameter of start_routine has the value of arg originally given to the respective call to pthread_create .

However, you cannot pass a pointer to CommandProcessor::operator()() to pthread_create for a much more important reason : it is a member function. All non- static class member functions need to be called with an object so that they can refer to this inside their body.

The solution to your problem is to make a static function that will match the prototype required by pthread_create , and pass the pointer to a CommandProcessor as the arg of pthread_create . Have a look at this :

static void* processor_executor(void *arg)
{
    CommandProcessor *processor = static_cast<CommandProcessor*>(arg);
    (*processor)();
    return NULL;
}

int main(int argc, char **argv)
{
    /* ... */
    for(int i=0; i < MAX_THREADS; i++)
    {
        pthread_create(&threads[i], NULL, processor_executor, static_cast<void*>        (processor));
    }
    /* ... */
}

This way, operator() is executed inside the thread created by pthread_create , using the same CommandProcessor object as the one in main() .

Keep in mind that accessing the same data from within many parallel threads will lead to data races. Use mutexes, semaphores, or condition variables to protect the data from parallel access.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM