Как вы вызываете pthread_create () для нестатической функции-члена извне класса [duplicate]

Инициализировать константы базы данных

Создать постоянное имя базы данных, имя пользователя, пароль, URL и драйверы, лимит опроса и т. д.

// init database constants
private static final String DATABASE_DRIVER = "com.mysql.jdbc.Driver";
private static final String DATABASE_URL = "jdbc:mysql://localhost:3306/database_name";
private static final String USERNAME = "root";
private static final String PASSWORD = "";
private static final String MAX_POOL = "250"; // set your own limit

Инициализировать Соединение и свойства

Как только соединение установлено, его лучше сохранить для целей повторного использования.

// init connection object
private Connection connection;
// init properties object
private Properties properties;

Создать свойства

Объект свойства содержит информацию о соединении, проверьте, уже ли он установлен.

// create properties
private Properties getProperties() {
    if (properties == null) {
        properties = new Properties();
        properties.setProperty("user", USERNAME);
        properties.setProperty("password", PASSWORD);
        properties.setProperty("MaxPooledStatements", MAX_POOL);
    }
    return properties;
}

Подключить базу данных

Теперь подключиться к базы данных с использованием констант и свойств, инициализированных.

// connect database
public Connection connect() {
    if (connection == null) {
        try {
            Class.forName(DATABASE_DRIVER);
            connection = DriverManager.getConnection(DATABASE_URL, getProperties());
        } catch (ClassNotFoundException | SQLException e) {
            // Java 7+
            e.printStackTrace();
        }
    }
    return connection;
}

Отключить базу данных

Как только вы закончите работу с базой данных, просто закройте соединение.

// disconnect database
public void disconnect() {
    if (connection != null) {
        try {
            connection.close();
            connection = null;
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Все вместе

Используйте этот класс MysqlConnect непосредственно после изменения имени_базы, имени пользователя и пароля и т. д.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

public class MysqlConnect {
    // init database constants
    private static final String DATABASE_DRIVER = "com.mysql.jdbc.Driver";
    private static final String DATABASE_URL = "jdbc:mysql://localhost:3306/database_name";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "";
    private static final String MAX_POOL = "250";

    // init connection object
    private Connection connection;
    // init properties object
    private Properties properties;

    // create properties
    private Properties getProperties() {
        if (properties == null) {
            properties = new Properties();
            properties.setProperty("user", USERNAME);
            properties.setProperty("password", PASSWORD);
            properties.setProperty("MaxPooledStatements", MAX_POOL);
        }
        return properties;
    }

    // connect database
    public Connection connect() {
        if (connection == null) {
            try {
                Class.forName(DATABASE_DRIVER);
                connection = DriverManager.getConnection(DATABASE_URL, getProperties());
            } catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            }
        }
        return connection;
    }

    // disconnect database
    public void disconnect() {
        if (connection != null) {
            try {
                connection.close();
                connection = null;
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

Как использовать?

Инициализировать класс базы данных.

// !_ note _! this is just init
// it will not create a connection
MysqlConnect mysqlConnect = new MysqlConnect();

Где-то еще в вашем коде ...

String sql = "SELECT * FROM `stackoverflow`";
try {
    PreparedStatement statement = mysqlConnect.connect().prepareStatement(sql);
    ... go on ...
    ... go on ...
    ... DONE ....
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    mysqlConnect.disconnect();
}

Это все :) Если что-нибудь улучшить, отредактируйте его! Надеюсь, это полезно.

70
задан Willi Mentzel 27 September 2015 в 18:58
поделиться

8 ответов

Вы не можете сделать это так, как вы его написали, потому что функции-члены класса C ++ имеют скрытый параметр this. pthread_create() не знает, какое значение this использовать, поэтому, если вы попытаетесь чтобы обойти компилятор, отбросив метод до указателя функции соответствующего типа, вы получите ошибку segmetnation. Вы должны использовать метод статического класса (который не имеет параметра this) или обычную функцию для начальной загрузки класса:

class C
{
public:
    void *hello(void)
    {
        std::cout << "Hello, world!" << std::endl;
        return 0;
    }

    static void *hello_helper(void *context)
    {
        return ((C *)context)->hello();
    }
};
...
C c;
pthread_t t;
pthread_create(&t, NULL, &C::hello_helper, &c);
128
ответ дан Adam Rosenfield 28 August 2018 в 03:14
поделиться

C ++: как передать функцию члена класса в pthread_create ()?

http://thispointer.com/c-how-to-pass-class -member-function-to-pthread_create /

typedef void * (*THREADFUNCPTR)(void *);

class C { 
   // ...
   void *print(void *) { cout << "Hello"; }
}

pthread_create(&threadId, NULL, (THREADFUNCPTR) &C::print, NULL);
-1
ответ дан Alberto 28 August 2018 в 03:14
поделиться

Слишком много раз я нашел способы решить то, о чем вы просите, на мой взгляд, слишком сложно. Например, вы должны определить новые типы классов, библиотеку ссылок и т. Д. Поэтому я решил написать несколько строк кода, которые позволяют конечному пользователю в принципе «thread -ize» «void :: method (void)» из любой класс. Конечно, это решение, которое я реализовал, может быть расширенным, улучшенным и т. Д., Поэтому, если вам нужны более конкретные методы или функции, добавьте их и, пожалуйста, будьте любезны, чтобы держать меня в цикле.

Вот 3 файла, которые показать, что я сделал.

    // A basic mutex class, I called this file Mutex.h
#ifndef MUTEXCONDITION_H_
#define MUTEXCONDITION_H_

#include <pthread.h>
#include <stdio.h>

class MutexCondition
{
private:
    bool init() {
        //printf("MutexCondition::init called\n");
        pthread_mutex_init(&m_mut, NULL);
        pthread_cond_init(&m_con, NULL);
        return true;
    }

    bool destroy() {
        pthread_mutex_destroy(&m_mut);
        pthread_cond_destroy(&m_con);
        return true;
    }

public:
    pthread_mutex_t m_mut;
    pthread_cond_t m_con;

    MutexCondition() {
        init();
    }
    virtual ~MutexCondition() {
        destroy();
    }

    bool lock() {
        pthread_mutex_lock(&m_mut);
        return true;
    }

    bool unlock() {
        pthread_mutex_unlock(&m_mut);
        return true;
    }

    bool wait() {
        lock();
        pthread_cond_wait(&m_con, &m_mut);
        unlock();
        return true;
    }

    bool signal() {
        pthread_cond_signal(&m_con);
        return true;
    }
};
#endif
// End of Mutex.h

// Класс, который инкапсулирует всю работу по потоковому методу (test.h):

#ifndef __THREAD_HANDLER___
#define __THREAD_HANDLER___

#include <pthread.h>
#include <vector>
#include <iostream>
#include "Mutex.h"

using namespace std;

template <class T> 
class CThreadInfo
{
  public:
    typedef void (T::*MHT_PTR) (void);
    vector<MHT_PTR> _threaded_methods;
    vector<bool> _status_flags;
    T *_data;
    MutexCondition _mutex;
    int _idx;
    bool _status;

    CThreadInfo(T* p1):_data(p1), _idx(0) {}
    void setThreadedMethods(vector<MHT_PTR> & pThreadedMethods)
    {
        _threaded_methods = pThreadedMethods;
      _status_flags.resize(_threaded_methods.size(), false);
    }
};

template <class T> 
class CSThread {
  protected:
    typedef void (T::*MHT_PTR) (void);
    vector<MHT_PTR> _threaded_methods;
    vector<string> _thread_labels;
    MHT_PTR _stop_f_pt;
    vector<T*> _elements;
    vector<T*> _performDelete;
    vector<CThreadInfo<T>*> _threadlds;
    vector<pthread_t*> _threads;
    int _totalRunningThreads;

    static void * gencker_(void * pArg)
    {
      CThreadInfo<T>* vArg = (CThreadInfo<T> *) pArg;
      vArg->_mutex.lock();
      int vIndex = vArg->_idx++;
      vArg->_mutex.unlock();

      vArg->_status_flags[vIndex]=true;

      MHT_PTR mhtCalledOne = vArg->_threaded_methods[vIndex];
      (vArg->_data->*mhtCalledOne)();
      vArg->_status_flags[vIndex]=false;
        return NULL;
    }

  public:
    CSThread ():_stop_f_pt(NULL), _totalRunningThreads(0)  {}
    ~CSThread()
    {
      for (int i=_threads.size() -1; i >= 0; --i)
          pthread_detach(*_threads[i]);

      for (int i=_threadlds.size() -1; i >= 0; --i)
        delete _threadlds[i];

      for (int i=_elements.size() -1; i >= 0; --i)
         if (find (_performDelete.begin(), _performDelete.end(), _elements[i]) != _performDelete.end())
              delete _elements[i];
    }
    int  runningThreadsCount(void) {return _totalRunningThreads;}
    int  elementsCount()        {return _elements.size();}
    void addThread (MHT_PTR p, string pLabel="") { _threaded_methods.push_back(p); _thread_labels.push_back(pLabel);}
    void clearThreadedMethods() { _threaded_methods.clear(); }
    void getThreadedMethodsCount() { return _threaded_methods.size(); }
    void addStopMethod(MHT_PTR p)  { _stop_f_pt  = p; }
    string getStatusStr(unsigned int _elementIndex, unsigned int pMethodIndex)
    {
      char ch[99];

      if (getStatus(_elementIndex, pMethodIndex) == true)
        sprintf (ch, "[%s] - TRUE\n", _thread_labels[pMethodIndex].c_str());
      else 
        sprintf (ch, "[%s] - FALSE\n", _thread_labels[pMethodIndex].c_str());

      return ch;
    }
    bool getStatus(unsigned int _elementIndex, unsigned int pMethodIndex)
    {
      if (_elementIndex > _elements.size()) return false;
      return _threadlds[_elementIndex]->_status_flags[pMethodIndex];
    }

    bool run(unsigned int pIdx) 
    {
      T * myElem = _elements[pIdx];
      _threadlds.push_back(new CThreadInfo<T>(myElem));
      _threadlds[_threadlds.size()-1]->setThreadedMethods(_threaded_methods);

      int vStart = _threads.size();
      for (int hhh=0; hhh<_threaded_methods.size(); ++hhh)
          _threads.push_back(new pthread_t);

      for (int currentCount =0; currentCount < _threaded_methods.size(); ++vStart, ++currentCount)
      {
                if (pthread_create(_threads[vStart], NULL, gencker_, (void*) _threadlds[_threadlds.size()-1]) != 0)
        {
                // cout <<"\t\tThread " << currentCount << " creation FAILED for element: " << pIdx << endl;
                    return false;
                }
        else
        {
            ++_totalRunningThreads;
             // cout <<"\t\tThread " << currentCount << " creation SUCCEDED for element: " << pIdx << endl;
                }
      }
      return true;
    }

    bool run() 
    {
            for (int vI = 0; vI < _elements.size(); ++vI) 
            if (run(vI) == false) return false;
          // cout <<"Number of currently running threads: " << _totalRunningThreads << endl;
        return true;
    }

    T * addElement(void)
    {
      int vId=-1;
      return addElement(vId);
    }

    T * addElement(int & pIdx)
    {
      T * myElem = new T();
      _elements.push_back(myElem);
      pIdx = _elements.size()-1;
      _performDelete.push_back(myElem);
      return _elements[pIdx];
    }

    T * addElement(T *pElem)
    {
      int vId=-1;
      return addElement(pElem, vId);
    }

    T * addElement(T *pElem, int & pIdx)
    {
      _elements.push_back(pElem);
      pIdx = _elements.size()-1;
      return pElem;
    }

    T * getElement(int pId) { return _elements[pId]; }

    void stopThread(int i)  
    {
      if (_stop_f_pt != NULL) 
      {
         ( _elements[i]->*_stop_f_pt)() ;
      }
      pthread_detach(*_threads[i]);
      --_totalRunningThreads;
    }

    void stopAll()  
    {
      if (_stop_f_pt != NULL) 
        for (int i=0; i<_elements.size(); ++i) 
        {
          ( _elements[i]->*_stop_f_pt)() ;
        }
      _totalRunningThreads=0;
    }
};
#endif
// end of test.h

// Использование пример файла «test.cc», который на linux я скомпилировал с классом, который инкапсулирует всю работу для потоковой реализации метода: g ++ -o mytest.exe test.cc -I. -lpthread -lstdc ++

#include <test.h>
#include <vector>
#include <iostream>
#include <Mutex.h>

using namespace std;

// Just a class for which I need to "thread-ize" a some methods
// Given that with OOP the objecs include both "functions" (methods)
// and data (attributes), then there is no need to use function arguments,
// just a "void xxx (void)" method.
// 
class TPuck
{
  public:
   bool _go;
   TPuck(int pVal):_go(true)
   {
     Value = pVal;
   }
   TPuck():_go(true)
   {
   }
   int Value;
   int vc;

   void setValue(int p){Value = p; }

   void super()
   {
     while (_go)
     {
      cout <<"super " << vc << endl;
            sleep(2);
         }
      cout <<"end of super " << vc << endl;
   }

   void vusss()
   {
     while (_go)
     {
      cout <<"vusss " << vc << endl;
      sleep(2);
     }
      cout <<"end of vusss " << vc << endl;
   }

   void fazz()
   {
     static int vcount =0;
     vc = vcount++;
     cout <<"Puck create instance: " << vc << endl;
     while (_go)
     {
       cout <<"fazz " << vc << endl;
       sleep(2);
     }
     cout <<"Completed TPuck..fazz instance "<<  vc << endl;
   }

   void stop()
   {
      _go=false;
      cout << endl << "Stopping TPuck...." << vc << endl;
   }
};


int main(int argc, char* argv[])
{
  // just a number of instances of the class I need to make threads
  int vN = 3;

  // This object will be your threads maker.
  // Just declare an instance for each class
  // you need to create method threads
  //
  CSThread<TPuck> PuckThreadMaker;
  //
  // Hera I'm telling which methods should be threaded
  PuckThreadMaker.addThread(&TPuck::fazz, "fazz1");
  PuckThreadMaker.addThread(&TPuck::fazz, "fazz2");
  PuckThreadMaker.addThread(&TPuck::fazz, "fazz3");
  PuckThreadMaker.addThread(&TPuck::vusss, "vusss");
  PuckThreadMaker.addThread(&TPuck::super, "super");

  PuckThreadMaker.addStopMethod(&TPuck::stop);

  for (int ii=0; ii<vN; ++ii)
  {
    // Creating instances of the class that I need to run threads.
    // If you already have your instances, then just pass them as a
    // parameter such "mythreadmaker.addElement(&myinstance);"
    TPuck * vOne = PuckThreadMaker.addElement();
  }

  if (PuckThreadMaker.run() == true)
  {
    cout <<"All running!" << endl;
  }
  else
  {
    cout <<"Error: not all threads running!" << endl;
  }

  sleep(1);
  cout <<"Totale threads creati: " << PuckThreadMaker.runningThreadsCount()  << endl;
  for (unsigned int ii=0; ii<vN; ++ii)
  {
    unsigned int kk=0;
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
  }

  sleep(2);
  PuckThreadMaker.stopAll();
  cout <<"\n\nAfter the stop!!!!" << endl;
  sleep(2);

  for (int ii=0; ii<vN; ++ii)
  {
    int kk=0;
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
  }

  sleep(5);
  return 0;
}

// End of test.cc
0
ответ дан Dodo 28 August 2018 в 03:14
поделиться

Мое предположение: это b / c, что он немного искалечен на C ++ b / c, отправив ему указатель на C ++, а не на указатель функции C. По-видимому, существует разность . Попробуйте выполнить

(void)(*p)(void) = ((void) *(void)) &c[0].print; //(check my syntax on that cast)

, а затем отправьте p.

Я также сделал то, что делаю с функцией-членом, но я сделал это в классе, который использовал его, и со статической функцией, которая, по-моему, сделала разницу.

-1
ответ дан EdH 28 August 2018 в 03:14
поделиться
7
ответ дан Jared Oberhaus 28 August 2018 в 03:14
поделиться

Мой любимый способ обработки потока - инкапсулировать его внутри объекта C ++. Вот пример:

class MyThreadClass
{
public:
   MyThreadClass() {/* empty */}
   virtual ~MyThreadClass() {/* empty */}

   /** Returns true if the thread was successfully started, false if there was an error starting the thread */
   bool StartInternalThread()
   {
      return (pthread_create(&_thread, NULL, InternalThreadEntryFunc, this) == 0);
   }

   /** Will not return until the internal thread has exited. */
   void WaitForInternalThreadToExit()
   {
      (void) pthread_join(_thread, NULL);
   }

protected:
   /** Implement this method in your subclass with the code you want your thread to run. */
   virtual void InternalThreadEntry() = 0;

private:
   static void * InternalThreadEntryFunc(void * This) {((MyThreadClass *)This)->InternalThreadEntry(); return NULL;}

   pthread_t _thread;
};

Чтобы использовать его, вы просто создадите подкласс MyThreadClass с использованием метода InternalThreadEntry (), который будет содержать цикл событий вашего потока. Конечно, вам нужно будет вызвать WaitForInternalThreadToExit () для объекта потока перед удалением объекта потока (и иметь некоторый механизм, чтобы убедиться, что поток действительно завершен, иначе WaitForInternalThreadToExit () никогда не вернется)

68
ответ дан Jeremy Friesner 28 August 2018 в 03:14
поделиться

Вышеупомянутые ответы хороши, но в моем случае 1-й подход, который преобразует функцию в статическую, не работает. Я пытался преобразовать код выхода, чтобы перейти в функцию потока, но этот код имел множество ссылок на нестатические члены класса. Второе решение инкапсулирования в объект C ++ работает, но имеет 3-уровневые оболочки для запуска потока.

У меня было альтернативное решение, которое использует существующую конструкцию C ++ - функцию «friend», и она отлично работала для моего дело. Пример того, как я использовал «друга» (будет использовать тот же пример для имен, показывающий, как его можно преобразовать в компактную форму с помощью друга)

    class MyThreadClass
    {
    public:
       MyThreadClass() {/* empty */}
       virtual ~MyThreadClass() {/* empty */}

       bool Init()
       {
          return (pthread_create(&_thread, NULL, &ThreadEntryFunc, this) == 0);
       }

       /** Will not return until the internal thread has exited. */
       void WaitForThreadToExit()
       {
          (void) pthread_join(_thread, NULL);
       }

    private:
       //our friend function that runs the thread task
       friend void* ThreadEntryFunc(void *);

       pthread_t _thread;
    };

    //friend is defined outside of class and without any qualifiers
    void* ThreadEntryFunc(void *obj_param) {
    MyThreadClass *thr  = ((MyThreadClass *)obj_param); 

    //access all the members using thr->

    return NULL;
    }

Конечно, мы можем использовать boost :: thread и избегайте всего этого, но я пытался изменить код C ++, чтобы не использовать boost (код был связан с boost именно для этой цели)

2
ответ дан sanmara 28 August 2018 в 03:14
поделиться

Мой первый ответ когда-либо в надежде, что он будет полезен кому-то: теперь я старый вопрос, но я столкнулся с той же ошибкой, что и вышеупомянутый вопрос, поскольку я пишу класс TcpServer, и я пытался используйте pthreads. Я нашел этот вопрос, и теперь я понимаю, почему это происходит. Я закончил это:

#include <thread>

метод для запуска threaded -> void* TcpServer::sockethandler(void* lp) {/*code here*/}

, и я вызываю его с помощью лямбда -> std::thread( [=] { sockethandler((void*)csock); } ).detach();

, что кажется чистым подходом ко мне.

1
ответ дан ZoOl007 28 August 2018 в 03:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: