I'm new in C++ and trying to create multiple threads with pthread.
typedef struct thread_args{
int &sockfd;
struct sockaddr_in &serv_addr;
int size_serv_addr;
socklen_t &clilen;
int &newsockfd;
};
void create_server(int &sockfd, struct sockaddr_in &serv_addr, int size_serv_addr, socklen_t &clilen, int &newsockfd){
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd;
socklen_t clilen;
pthread_t t1;
struct sockaddr_in serv_addr, cli_addr;
struct thread_args *args;
args->clilen = clilen;
args->newsockfd = newsockfd;
args->serv_addr = serv_addr;
args->size_serv_addr = sizeof(serv_addr);
args->sockfd = sockfd;
pthread_create(&t1, NULL, create_server, &args);
printf("hello abc");
return 0;
}
When I run this code, it has a message:
error:/bin/sh -c 'make -j 4 -e -f error: invalid conversion from 'void* (*)(int&, sockaddr_in&, int, socklen_t&, int&) {aka void* (*)(int&, sockaddr_in&, int, unsigned int&, int&)}' to 'void* (*)(void*)' [-fpermissive]
pthread_create(&t1, NULL, create_server, &args);
How can I fix this?
Signature for your thread function should be:
void *(*start_routine) (void *)
but you provide:
void create_server(int &sockfd, struct sockaddr_in &serv_addr, int size_serv_addr, socklen_t &clilen, int &newsockfd)
you should create a function like:
void* myThread(void *arg);
then args argument in pthread_create call will be passed as arg parameter to myThread, you can use its fields to call create_server
Your function definition does not match the type pthread_create wants to have. It requires only 1 arguments and that is a void* (so a function void function(void* args)).
you need to change create_server to
void create_server(void* voidArgs) {
thread_args* args = static_cast<thread_args*>(voidArgs);
//...
}
You will not have those issues though if you use the c++11 std::thread object. There you can directly use the argument type and with any number of arguments you like. So you don't have to define the thread_args struct.
Related
I have a working example in single file with its spapidllm64.h but wanna split into separate files for easier coding. I have tried to reduce it into a minimal version as follows:
// spapidll.h
#define SPDLLCALL __stdcall
typedef void (SPDLLCALL *LoginReplyAddr)(char *user_id, long ret_code, char *ret_msg);
typedef void (SPDLLCALL *p_SPAPI_RegisterLoginReply)(LoginReplyAddr addr);
typedef int (SPDLLCALL *p_SPAPI_Login)();
//main.cpp
void SPDLLCALL LoginReply(char *user_id, long ret_code, char *ret_msg);
p_SPAPI_RegisterLoginReply SPAPI_RegisterLoginReply;
p_SPAPI_Login SPAPI_Login;
int main(void)
{
HINSTANCE hInst = LoadLibrary("spapidllm64.dll");
SPAPI_RegisterLoginReply = (p_SPAPI_RegisterLoginReply)GetProcAddress(hInst, "SPAPI_RegisterLoginReply");
SPAPI_RegisterLoginReply(LoginReply);
SPAPI_Login = (p_SPAPI_Login)GetProcAddress(hInst, "SPAPI_Login");
int rc = SPAPI_Login();
printf("\nSPAPI_Login: %d\n", rc);
Sleep(3000);
FreeLibrary(hInst);
return 0;
}
void SPDLLCALL LoginReply(char *user_id, long ret_code, char *ret_msg)
{
printf("\nLoginReply[%s]: Ret code: %d, Ret msg: %s",user_id, ret_code, (ret_code == 0)?"OK":ret_msg);
}
now I want to put those codes into a class like this:
// test.h
class ApiTester
{
public:
HINSTANCE hInst;
ApiTester(void){
hInst = LoadLibrary("spapidllm64.dll");
}
~ApiTester(void){
FreeLibrary(hInst);
}
void RegisterDLL();
int Login();
void SPDLLCALL LoginReply(char *user_id, long ret_code, char *ret_msg);
void SPDLLCALL ConnectingReply(long host_type, long con_status);
p_SPAPI_RegisterLoginReply SPAPI_RegisterLoginReply;
p_SPAPI_RegisterConnectingReply SPAPI_RegisterConnectingReply;
p_SPAPI_Login SPAPI_Login;
};
// test.c
#include "tester.h"
void ApiTester::RegisterDLL()
{
SPAPI_RegisterLoginReply = (p_SPAPI_RegisterLoginReply)GetProcAddress(hInst, "SPAPI_RegisterLoginReply");
SPAPI_RegisterLoginReply(LoginReply); // Error E0167 C3867
SPAPI_Login = (p_SPAPI_Login)GetProcAddress(hInst, "SPAPI_Login");
}
int ApiTester::Login()
{
int rc = SPAPI_Login();
printf("\nSPAPI_Login: %d\n", rc);
}
void SPDLLCALL ApiTester::LoginReply(char *user_id, long ret_code, char *ret_msg){
printf("\nLoginReply[%s]: Ret code: %d, Ret msg: %s",user_id, ret_code, (ret_code == 0)?"OK":ret_msg);
}
Then Windows VS C++ shows this error:
Error (active) E0167 argument of type "void (__stdcall ApiTester::*)(char *user_id, long ret_code, char *ret_msg)" is incompatible with parameter of type "LoginReplyAddr"
Error C3867 'ApiTester::LoginReply': non-standard syntax; use '&' to create a pointer to member
Not sure why it works in single file but couldn't work in this way. I thought it should be straight-forward(Hopefully, there is no typo). I'd be appreciate if there is any help.
typedef void (SPDLLCALL *LoginReplyAddr)(char *user_id, long ret_code, char *ret_msg);
typedef void (SPDLLCALL *p_SPAPI_RegisterLoginReply)(LoginReplyAddr addr);
According to the definition above, LoginReplyAddr is a function pointer, not a class member function pointer.
void ApiTester::RegisterDLL()
{
SPAPI_RegisterLoginReply = (p_SPAPI_RegisterLoginReply)GetProcAddress(hInst, "SPAPI_RegisterLoginReply");
SPAPI_RegisterLoginReply(LoginReply); // Error E0167 C3867
...
In this code, LoginReply is class member function pointer.
void (__stdcall ApiTester::*)(char *user_id ...
I guess that is the problem.
If you want to use the class member function as a callback, you also have to pass the 'this' of the class.
Or you can use the static member function.
The link below could help you.
Using a C++ class member function as a C callback function
On Debian I try to mock system function bind to bind an interface address to a socket. To set an ip address I think I have to use side effects on a parameter of bind. I use this code:
extern "C" {
int mysocket();
}
// --- mock bind -------------------------------------------
class BindInterface {
public:
virtual ~BindInterface() {}
virtual int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen) = 0;
};
class BindMock : public BindInterface {
public:
virtual ~BindMock() {}
MOCK_METHOD(int, bind, (int, const struct sockaddr*, socklen_t), (override));
};
BindInterface* ptrBindMockObj = nullptr;
int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen) {
return ptrBindMockObj->bind(sockfd, addr, addrlen);
}
TEST(MockTestSuite, bind_address_to_a_socket)
{
using ::testing::_;
using ::testing::Return;
using ::testing::DoAll;
using ::testing::SetArgPointee;
using ::testing::SetArgReferee;
struct sockaddr_in my_addr = {0};
BindMock bindMockObj;
ptrBindMockObj = &bindMockObj;
my_addr.sin_family = AF_INET;
EXPECT_EQ(inet_pton(AF_INET, "192.168.55.66", &my_addr.sin_addr.s_addr), 1);
EXPECT_CALL(bindMockObj, bind(_, _, _))
.WillOnce(DoAll(SetArgPointee<1>((struct sockaddr*)my_addr),
SetArgReferee<2>(sizeof(my_addr)),
Return(0)));
EXPECT_EQ(mysocket(), EXIT_SUCCESS);
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
It doesn't work because the compiler complains invalid cast as follows:
test_mylib.cpp: In member function ‘virtual void MockTestSuite_bind_address_to_a_socket_Test::TestBody()’:
test_mylib.cpp:52:42: error: invalid cast from type ‘sockaddr_in’ to type ‘sockaddr*’
52 | .WillOnce(DoAll(SetArgPointee<1>((struct sockaddr*)my_addr),
| ^~~~~~~~~~~~~~~~~~~~~~~~~
Seems I do not really understand what SaveArgPointee<N>(pointer) is doing. What I'm doing wrong with types and cast?
UPDATE:
With the suggestion from the answer of #Quarra to define the ACTION_P outside the TEST body I get two error messages within a bunch of stacked calls:
googlemock/include/gmock/gmock-actions.h:1116:56: error: static assertion failed: Argument must be a reference type.
1116 | static_assert(std::is_lvalue_reference<argk_type>::value,
| ^~~~~^
--- snip ---
test_mylib.cpp:33:54: error: no match for ‘operator=’ (operand types are ‘sockaddr’ and ‘const sockaddr_in’)
33 | ACTION_P(AssignSockAddr, param) { *(sockaddr*)(arg0) = param; }
| ~~~~~~~~~~~~~~~~~~~^~~~~~~
In file included from /usr/include/x86_64-linux-gnu/sys/socket.h:33,
from /usr/include/netinet/in.h:23,
from test_mylib.cpp:7:
I agree that it's strange that your example doesn't compile: it's trying to change the pointer to const socaddr, not const pointer...
You can define your own action and use it like that:
ACTION_P(AssignSockAddr, param) { *(sockaddr*)(arg0) = param; }
TEST(MockTestSuite, bind_address_to_a_socket) {
// [ rest of the test code here ]
EXPECT_CALL(bindMockObj, bind(_, _, _)).WillOnce(
DoAll(WithArg<1>(AssignSockAddr(my_addr)),
SetArgReferee<2>(sizeof(my_addr)),
Return(0)));
EXPECT_EQ(mysocket(), EXIT_SUCCESS);
}
I have defined the following structure:
struct com_NetworkStruct
{
enum com_NetworkStatus status;
char IPV4_Addr[COM_IPV4_ADDR_LENGTH];
char IPV4_Netmask[COM_IPV4_ADDR_LENGTH];
char IPV4_DNS1[COM_IPV4_ADDR_LENGTH];
char IPV4_DNS2[COM_IPV4_ADDR_LENGTH];
int IPV4_DHCP_Enabled;
int IPV6_Supported;
int IPV6_Enabled;
struct com_IPv6_Data *IPV6_Address_List;
char HW_Addr[COM_ETH_MAC_ADDR_LENGTH];
int MTU_Size;
int Link_Speed;
enum com_LinkType Link_Type;
};
And the following method definition:
int foo(struct com_NetworkStruct **netinfo);
This is the main function and how i call the function:
int main(int argc, char const *argv[])
{
int ret;
char data_aux[200];
struct com_NetworkStruct *netinfo = NULL;
ret = foo(&netinfo);
memset(data_aux, 0, sizeof(data_aux));
sprintf(data_aux, "%s", netinfo->IPV4_Addr);
cout<<string(data_aux)<<endl;
return 0;
}
The problem is when I try to read the data of the IPV4_Addr value since it sends me the following error:
Error: #289: no instance of constructor "std::basic_string<_CharT, Traits, Alloc>::basic_string [with CharT=char, Traits=std::char_traits<char>, _Alloc=std::allocator<char>]" matches the argument list
argument types are: (const char [20], char [16])
I already tried this, but nothing works:
&netinfo->IPV4_Addr
netinfo.IPV4_Addr
string(netinfo->IPV4_Addr)
my code:
#include "xception.h"
#include <iostream>
#include <stdio.h>
#include <signal.h>
#include <stdio.h>
#include <signal.h>
#include <execinfo.h>
void bt_sighandler(int sig, struct sigcontext ctx)
{
void *trace[16];
char **messages = (char **)NULL;
int i, trace_size = 0;
trace_size = backtrace(trace, 16);
/* overwrite sigaction with caller's address */
trace[1] = (void *)ctx.eip;
messages = backtrace_symbols(trace, trace_size);
/* skip first stack frame (points here) */
printf("[bt] Execution path:\n");
for (i=1; i<trace_size; ++i)
{
printf("[bt] #%d %s\n", i, messages[i]);
char syscom[256];
sprintf(syscom,"addr2line %p -e sighandler", trace[i]);
system(syscom);
}
}
void xception::initialize_xception()
{
/* Install our signal handler */
struct sigaction sa;
sa.sa_handler = (void *)bt_sighandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(SIGUSR1, &sa, NULL);
}
THis is giving me the error : r#r-HP-Mini-110:~/l33t/freeln/Xception/source$ g++ -std=c++11 -g -rdynamic -Wall -o xcep_app application.cpp xception.cpp
xception.cpp: In static member function ‘static void xception::initialize_xception()’:
xception.cpp:38:28: error: invalid conversion from ‘void*’ to ‘__sighandler_t {aka void (*)(int)}’ [-fpermissive]
Strange thing is that the same thing earlier compiled when placed like as follows:
#include <stdio.h>
#include <signal.h>
#include <stdio.h>
#include <signal.h>
#include <execinfo.h>
void bt_sighandler(int sig, struct sigcontext ctx)
{
void *trace[16];
char **messages = (char **)NULL;
int i, trace_size = 0;
trace_size = backtrace(trace, 16);
/* overwrite sigaction with caller's address */
trace[1] = (void *)ctx.eip;
messages = backtrace_symbols(trace, trace_size);
/* skip first stack frame (points here) */
printf("[bt] Execution path:\n");
for (i=1; i<trace_size; ++i)
{
printf("[bt] #%d %s\n", i, messages[i]);
char syscom[256];
sprintf(syscom,"addr2line %p -e sighandler", trace[i]); //last parameter is the name of this app
system(syscom);
}
}
int func_a(int a, char b) {
char *p = (char *)0xdeadbeef;
//a = a + b;
//*p = 10; /* CRASH here!! */
a =9;
return 2*a;
}
int func_b() {
int res, a = 5;
res = 5 + func_a(a, 't');
raise(SIGUSR1);
return res;
}
int main() {
/* Install our signal handler */
struct sigaction sa;
sa.sa_handler = (void *)bt_sighandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
//sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGUSR1, &sa, NULL);
/* ... add any other signal here */
/* Do something */
printf("%d\n", func_b());
printf("%s\n", "not dead yet :)");
}
Can you please point me out my mistake ?
Regardless of how you slice it, you cannot use
void bt_sighandler(int sig, struct sigcontext ctx)
function where a void (int) callback is required. You might succeed in suppressing error messages by using casts, which will make the code to formally "compile", but this will not make your program work in any meaningful sense of the word "work".
Function for sa.sa_handler callback must be a void (int) function, period. There's no way around it. If you want to "smuggle" some additional external data into that function, you have to invent an alternative solution. You can't just add arbitrary parameters to callback functions and expect that the caller will somehow magically supply proper arguments for the parameters you added.
The sa_handler member of struct sigaction is a function pointer of type void(*) (int). In contrast, the type of the expression (void *)ctx.eip is void * because of the cast. In C++, implicit conversion from void * to another pointer type does not happen, hence the error.
The difference is that in C you can implicitly convert a void * to any other pointer type, while in C++ you cannot.
In C++ you need an explicit cast to the actual function type (void (*)(int)) to make it not an error.
Note that in both C and C++ converting a void * to a function pointer is undefined behavior, but will usually work if the void * was converted from a compatible function pointer in the first place. In addition, a function pointer is only guarenteed to be completely compatible if all the argument types are exactly the same, though you can often get something that appears to work with different argument types (undefined behavior again).
Any comment is appreciated for the compile error below.
Although my question is similar to other thread: pthread function from a class, I still haven't been able to solve my problem. I am still not that familliar with pointer, and thread programming in C & C++.
Error
../src/Main.cpp: In function ‘int main(int, char**)’:
../src/Main.cpp:22: error: invalid conversion from ‘unsigned int* (*)(void*)’ to ‘void* (*)(void*)’
../src/Main.cpp:22: error: initializing argument 3 of ‘int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)’
make: *** [src/Main.o] Error 1
Main.cpp
#include <process.h>
#include "ThreadInstance.hpp"
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char** argv)
{
pthread_mutex_t mutex;
int ht1;
pthread_t threadId1;
pthread_attr_t attr1;
pthread_mutex_init(&mutex, NULL);
pthread_attr_init(&attr1);
pthread_attr_setdetachstate(&attr1, PTHREAD_CREATE_DETACHED);
ht1 = pthread_create(&threadId1,
&attr1,
&ThreadInstance::ThreadEntryPoint,
//(void *)readThread);
NULL);
unsigned long rc = 0;
rc = pthread_join(ht1, NULL);
return 0;
}
ThreadInstance.hpp
#ifndef _SCENE_CLASSIFY_THREAD_H
#define _SCENE_CLASSIFY_THREAD_H
#ifndef STDCALL
#define STDCALL __attribute__((stdcall))
#endif
using namespace std;
class ThreadInstance
{
public:
ThreadInstance();
ThreadInstance(int camNum);
void startUp();
static unsigned STDCALL* ThreadEntryPoint(void* pThis)
{
//static unsigned __stdcall ThreadEntryPoint(void* pThis) {
ThreadInstance *ptr = (ThreadInstance*) pThis;
ptr->startUp();
//return 1; // Returns error "invalid conversion from ‘int’ to ‘unsigned int*’" when the function is declared as pointer.
// Since returning either 1 or 0,
// compile error still occurs.
// So this return value should not be the cause.
return 0;
}
~ThreadInstance();
};
#endif
Note: Only necessary part is shown
Your ThreadEntryPoint must return void*.
The error indicates the type that is expected, and that is the function pointer type that you are required to use.
The start function returns void* and takes void*. Yours returns unsigned int*.
Change the method to return a pointer to void.