简体   繁体   English

在pthread_create中使用仿函数

[英]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. CommandProcessor(functor)运行此命令。 Pointer of this class I try to throw to pthread_create. 我尝试将此类的指针扔给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 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 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 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* . 免责声明:这是您实际上不应该在C ++中做的事情,因为它包括弄乱void* It needs to be used here because of the interaction with the C API. 由于与C API的交互,因此需要在此处使用它。 If you can, use std::thread from C++11 or boost::thread if you're using an older compiler. 如果可以,请使用C ++ 11中的std :: thread ;如果使用的是较旧的编译器,请使用boost :: thread

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. 要回答你的问题:是的,一旦为它实现了operator() ,就可以将一个类对象作为可调用的对象(作为“函数”)。 You already did that, but the problem is the extra code needed to implement the interface between C++ and the C API for Pthreads. 您已经做到了,但是问题是实现C ++和Pthreads的C API之间的接口所需的额外代码。

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. 出现“无法将processor用作功能”错误的主要原因是processorCommandProcessor* ,因此需要取消引用。 However, even doing (*processor)() wouldn't help you, because pthread_create is defined as follows : 但是,即使执行(*processor)()也无济于事,因为pthread_create的定义如下:

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* . 这意味着要执行的函数必须返回void*并采用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 . 该文档还指出, start_routinearg最初将arg的值arg赋予了对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. 但是,由于更重要的原因,您不能将指向CommandProcessor::operator()()的指针传递给pthread_create :它是成员函数。 All non- static class member functions need to be called with an object so that they can refer to this inside their body. 所有非static类的成员函数需要一个对象被调用,以便他们可以参考this自己的身体里面。

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 . 解决您的问题的方法是制作一个与pthread_create所需原型相匹配的静态函数,并将指针作为pthread_createarg传递给CommandProcessor 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() . 这样, operator()pthread_create创建的线程内执行,使用与main()相同的CommandProcessor对象。

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. 使用互斥量,信号量或条件变量来保护数据免受并行访问。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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