3

I search all the net for answer, but I didn't find any solution. Can you please help. My problem is I am trying to send Lambda to another function and use Pthread library to run the lambda across several threads. Next is the code:

  1    #include <iostream>
  2    #include <stdlib.h>
  3    #include <pthread.h>
  4    #include <vector>
  5 
  6    using namespace std;
  7 
  8 
  9   template<class InputIt, class Function>
 10    inline Function parallel_fun(InputIt first, InputIt last, Function f)
 11    {
 12         pthread_t threads[4];
 13 
 14       for (int i=0; first != last; ++first) {
 15 
 16          pthread_create(&threads[i], nullptr,f , nullptr);
 17 
 18           i++;
 19        }
 20 
 21      for (int i=0; i<4;i++) {
 22 
 23          pthread_join(threads[i],nullptr);
 24 
 25 
 26        }
 27 
 28 
 29 
 30 
 31    return f;
 32   }
 33 
 34 
 35    int main()
 36   {
 37    int z=90;
 38    vector<int> a(4);
 39     a[0]=1; a[1]=2;
 40     parallel_fun(a.begin(), a.end(), [=](void* data) -> void*
 41                     {
 42          cout<<"test"<<z<<endl;
 43            //do something
 44          });
 45 
 46 
 47 
 48 return 0;
 49 }

I compile using the following line: g++ -std=c++0x -pthread test.cpp -o a

and I receive this error:

test.cpp: In function ‘Function parallel_fun(InputIt, InputIt, Function) [with InputIt = __gnu_cxx::__normal_iterator<int*, std::vector<int> >, Function = main()::<lambda(void*)>]’:
test.cpp:44:11:   instantiated from here
test.cpp:16:10: error: cannot convert ‘main()::<lambda(void*)>’ to ‘void* (*)(void*)’ for argument ‘3’ to ‘int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)’
Morwenn
  • 21,684
  • 12
  • 93
  • 152
user2521791
  • 1,621
  • 2
  • 14
  • 13
  • 3
    I suspect you have to either switch to C++ 11 multithreading support, or give up on lambdas. I don't know how lambdas are implemented, but I would be surprised if they could be passed directly to C API's – Nicola Musatti Jun 25 '13 at 22:19

2 Answers2

6

I am not sure about the new C++11 API. I don't think I have enough time to learn new API.

This is your lucky day. The C++11 API was strongly influenced by pthreads. There is nearly a mechanical translation. Here is your code cast in C++11:

#include <iostream>
#include <stdlib.h>
#include <thread>
#include <vector>

template<class InputIt, class Function>
inline
Function
parallel_fun(InputIt first, InputIt last, Function f)
{
    std::thread threads[4];
    for (int i=0; first != last; ++first)
    {
        threads[i] = std::thread(f);
        i++;
    }
    for (int i=0; i<4;i++)
    {
        threads[i].join();
    }
    return f;
}


int main()
{
    int z=90;
    std::vector<int> a(4);
    a[0]=1; a[1]=2;
    parallel_fun(a.begin(), a.end(), [=]()
                                      {
                                        std::cout<<"test" << z << std::endl;
                                        //do something
                                      });
}

Your alternative, is to figure out how std::thread gets implemented on top of pthreads, which trust me, is much more complicated than the C++11 translation shown above.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • 2
    This is not an answer to the question. Maybe OP is satisfied with this alternative but definitely not everyone coming to that question looking for an answer. – Winter Jun 22 '17 at 15:22
  • @Howard Hinnant, how will behave your code if we will change the `std::vector a(4)` to the `std::vector a(10)`? – Serge Roussak Sep 21 '17 at 05:50
  • This was a faithful translation of the OP's code, nothing more, nothing less. Any bugs in the OP's code also got translated into C++11. – Howard Hinnant Sep 21 '17 at 14:35
  • What if my lambda function takes an argument say [=](int x){...}, how would I call using thread? std::thread(f)?. – srccode Jan 08 '19 at 06:17
3

There is no conversion from a lambda to a function pointer unless the lambda has no captures. (§5.1.2p6). So if you require the capture of z, you are out of luck.

The C interface expects you to use the void* argument for your closures. You could do that, which would be ugly (but C-like), or you could use the new C++11 thread support library, if your C++ environment supports it.

rici
  • 234,347
  • 28
  • 237
  • 341
  • 1
    I need to capture local variables and use then inside Lambda. I notice that if I remove z from the code the program compile without error. – user2521791 Jun 25 '13 at 22:29
  • anyway thank you for your help. I am not sure about the new C++11 API. I don't think I have enough time to learn new API. – user2521791 Jun 25 '13 at 22:34
  • IMHO one is best off learning C++11 thread support, which isn't that complicated to begin with, considering that you know POSIX threads. – E_net4 Jun 25 '13 at 22:57