pthread passing object as argument to pthread_create

14,601

Solution 1

This will likely do what you want. I just threw it together so I apologize in advance if there are any syntax errors. It addresses your two issues (incorrect third and fourth parameters to pthread_create()) as well as uses RAII for allocation management:

#include <iostream>
#include <vector>

using namespace std;

struct Node
{
    int value;
};

void *start(void* p)
{
    Node* obj = (Node*)p;
    cout << obj->value;
    return NULL;
}

int main(int argc, char *argv[])
{
    int n;
    cin >> n;
    if (n <= 0)
        return EXIT_FAILURE;

    std::vector<Node> nodes(n);
    std::vector<pthread_t> threads(n);
    for (int i=0;i<n;++i)
        pthread_create(threads.data()+i, NULL, &start, nodes.data()+i);

    std::for_each(threads.begin(), threads.end(),
                  [](pthread_t& t) { pthread_join(t, NULL); });

    return EXIT_SUCCESS;
}

C++11 Threads : Their What's For Dinner

I would advise using the C++11 threading classes and objects (thread, mutex, condition_variable, etc) over using raw-pthreads. They really are the bee's knees. Something similar (though with an auto-calculated N) appears below:

#include <iostream>
#include <vector>
#include <thread>
#include <memory>
using namespace std;

struct Node
{
    int value;
    Node() : value() {}

    // member function we're using as thread proc
    void thread_proc(int n)
    {
        value = n;
    }
};

int main(int argc, char *argv[])
{
    // allocate nodes
    vector<Node> nodes(std::max(std::thread::hardware_concurrency()+1, 4U));

    // starts threads
    vector<thread> threads;
    for (int i=0; i<nodes.size(); ++i)
        threads.emplace_back(std::bind(&Node::thread_proc, nodes.data()+i, i+1));

    // wait for all threads to complete.
    for(auto &t : threads)
        t.join();

    // proof we really did hit *our* nodes in the threads.
    for (auto& node : nodes)
        cout << "Node value: " << node.value << endl;

    return EXIT_SUCCESS;
}

Output

Node value: 1
Node value: 2
Node value: 3
Node value: 4
Node value: 5

Solution 2

The compiler is complaining about argument 3, the start_routine. The start routine (3rd argument to pthread_create) is specified this way: void *(*start_routine)(void *) a pointer to a method, that takes one void pointer (void *) as an argument and returns a void pointer (void *).

Your code is passing a start as the 3rd argument.

void start(void *n){
    ...
}

A mismatch to what the function is declared to take as the 3rd argument.

Changing your start to:

void *start(void *n) {
  return NULL;
}

Will make the error go away. The value returned from the method acts as the exit code of the thread, unless you are calling pthread_exit.

Solution 3

The linux manual page for pthread_create() contains a good example.

The thread_start function signature is

void * thread_start(void *arg)

In the main function you can see how to pass arguments (&tinfo[tnum]).

pthread_create(&tinfo[tnum].thread_id, &attr, &thread_start, &tinfo[tnum]);

Note that each thread recieves a distinct set of arguments.

Solution 4

The return type of the thread function must be void *;

void* start(void *n)
{
//Code
}

Secondly, you must send the argument to the function this way:

pthread_create(&p[i],NULL,start,(void *)(&nodeObj[i])); 

The requirement of argument passing is that the passed object must be a pointer to something. Even though nodeObj is a pointer, when you use array notation like nodeObj[i] you dereference it. Hence use the ampersand. &nodeObj[i];

You can also simply use (nodeObj+i);

Share:
14,601
Shehbaz Jaffer
Author by

Shehbaz Jaffer

Updated on June 04, 2022

Comments

  • Shehbaz Jaffer
    Shehbaz Jaffer about 2 years

    For the given program ::

    void start(void *n){
      Node *obj = (Node *)n;
      cout << obj -> val;
    }
    
    int   
    main(int argc, char *argv[])
    {
      int i,n;
      cin >> n;
      Node *nodeObj;
      nodeObj = new Node[n];
      pthread_t *p = new pthread_t[n];
      for(i=0;i<n;i++){
        pthread_create(&p[i],NULL,start,(void *)(nodeObj[i]));   /*ERROR HERE in arg pass*/
      }                                                                               
      return 0;   
    }
    

    I get the following error::

    invalid conversion from ‘void ()(void)’ to ‘void* ()(void)’

    I basically want to send each of the object NodeObj[0] , NodeObj[1] , NodeObj[2] ... to each of the new threads I create. the start function is where each of the threads start.