Multiple arguments (with struct) error using pthread - c++

I'm working on a multiclient chat project.
Here is my code:
struct RecvDataModel
{
int sockAddr;
char *inData;
};
void *ProcessData(void *arg);
void Client::Recv(int sockAddr, char *inData)
{
RecvDataModel outData;
outData.sockAddr = sockAddr;
outData.inData = inData;
pthread_t rThr;
pthread_create(&rThr, NULL, ProcessData, (void*)&outData);
}
void *ProcessData(void *arg)
{
RecvDataModel *inData = (RecvDataModel*)arg;
cout << inData->inData << endl;
return 0;
}
Basically if sockAddr (in Client::Recv) equals "55" ProcessData's cout function writing "31784736", if equals "0" cout's "5120"
That's my big problem! I can't continue without this! (I'm using eclipse C++)
What's the problem? I have already looked some example projects like this: Link >>>

You're passing a pointer to a RecvDataModel which is a function-local variable. It will go out of scope at the end of the Client::Recv function.
Try allocating it with new instead:
RecvDataModel * outData = new RecvDataModel();
outData->sockAddr = sockAddr;
outData->inData = inData;
pthread_t rThr;
pthread_create(&rThr, NULL, ProcessData, outData);

Don't pass around pointers to local variables that go out of scope. As soon as you create that thread, outData isn't valid anymore, and so the pointer you gave to it is no good. You need to declare outData with a static qualifier, or allocate space for it dynamically so that it doesn't vanish when Client::Recv returns.

Related

Using pthreads in C++

I need to use pthreads in C++ but I can't use the function pthread_create, it shows me an error. Also, I need to pass multiple parameters to a method:
void Read(int socks, int client) {
while (1) {
int n;
char buffer1[256];
bzero(buffer1, 256);
n = read(socks, buffer1, 255);
if (n < 0) {
perror("ERROR leyendo el socket");
exit(1);
}
cout << "Mensaje de cliente " << client << ":" << buffer1 << endl;
Jsons json1;
json1.parseJson(buffer1);
writeMsg(socks, "hola\n");
}
}
void ThreadServer::Thread(int sock, int client) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_t tid;
pthread_create(&tid,&attr,Read);
}
If I understand you correctly, you want to send multiple parameters to a thread. The thread functions for pthread take a single void *.
void threadfn(void *data);
you just need to create a data structure to hold your parameters
struct threadData
{
int param1;
int param2;
};
declare your struct and assign parameter values. When you call pthread_create, pass the struct pointer.
struct threadData data = {1,2};
pthread_create(&tid, &attr, Read, &data);
when you get the pointer in read function, cast and use it to extract parameters.
void Read( void * thrData)
{
struct threadData *myParams = (struct threadData*)thrData;
.
.
.

How to pass struct to a new thread (C++)

So, I am writing a small winsock app and I need to make a multi-client server.
I decided to use threads for every new connection, the problem is that I don't know how to pass multiple data to a thread, so I use struct.
Struct:
typedef struct s_par {
char lttr;
SOCKET clientSocket;
} par;
_stdcall:
unsigned __stdcall ClientSession(void *data) {
par param = data;
char ch = param.lttr;
SOCKET clntSocket = param.clientSocket;
// ..working with client
}
Main:
int main() {
unsigned seed = time (0);
srand(seed);
/*
..........
*/
SOCKET clientSockets[nMaxClients-1];
char ch = 'a' + rand()%26;
while(true) {
cout << "Waiting for clients(MAX " << nMaxClients << "." << endl;
while ((clientSockets[nClient] = accept(soketas, NULL, NULL))&&(nClient < nMaxClients)) {
par param;
// Create a new thread for the accepted client (also pass the accepted client socket).
if(clientSockets[nClient] == INVALID_SOCKET) {
cout << "bla bla" << endl;
exit(1);
}
cout << "Succesfull connection." << endl;
param.clientSocket = clientSockets[nClient];
param.lttr = ch;
unsigned threadID;
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &ClientSession, &param, 0, &threadID);
nClient++;
}
The problem is that I get errors with data type conversion. Maybe someone could suggest an easy fix with passing this struct to a thread?
With each round of your while-loop you're doing two ill-advised activites:
Passing the address of an automatic variable that will be destroyed with each cycle of the loop.
Leaking a thread HANDLE returned from _beginthreadex
Neither of those is good. Ideally your thread proc should look something like this:
unsigned __stdcall ClientSession(void *data)
{
par * param = reinterpret_cast<par*>(data);
char ch = param->lttr;
SOCKET clntSocket = param->clientSocket;
// ..working with client
delete param;
return 0U;
}
And the caller side should do something like this:
par *param = new par;
param->clientSocket = clientSockets[nClient];
param->lttr = ch;
...
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &ClientSession, param, 0, &threadID);
if (hThread != NULL)
CloseHandle(hThread);
else
delete param; // probably report error here as well
That should be enough to get you going. I would advise you may wish to take some time to learn about the C++11 Threading Model. It makes much of this considerably more elegant (and portable!).
Best of luck.

multiple buffers using threads

I need some algorithm help with a multithreaded program I'm writing. It's basically the cp command in unix, but with a read thread and a write thread. I'm using semaphores for thread synchronization. I have structs for buffer and thread data defined as
struct bufType {
char buf[BUFFER_SIZE];
int numBytes;
};
struct threadData {
int fd;
bufType buf;
};
and a global array of bufType. Code for my main is
int main(int argc, const char * argv[])
{
int in, out;
pthread_t Producer, Consumer;
threadData producerData, consumerData;
if (argc != 3)
{
cout << "Error: incorrect number of params" << endl;
exit(0);
}
if ((in = open(argv[1], O_RDONLY, 0666)) == -1)
{
cout << "Error: cannot open input file" << endl;
exit(0);
}
if ((out = open(argv[2], O_WRONLY | O_CREAT, 0666)) == -1)
{
cout << "Cannot create output file" << endl;
exit(0);
}
sem_init(&sem_empty, 0, NUM_BUFFERS);
sem_init(&sem_full, 0, 0);
pthread_create (&Producer, NULL, read_thread, (void *) &producerData);
pthread_create (&Consumer, NULL, write_thread, (void *) &consumerData);
pthread_join(Producer, NULL);
pthread_join(Consumer, NULL);
return 0;
}
and read and write threads:
void *read_thread(void *data)
{
threadData *thread_data;
thread_data = (threadData *) data;
while((thread_data->buf.numBytes = slow_read(thread_data->fd, thread_data->buf.buf, BUFFER_SIZE)) != 0)
{
sem_post(&sem_full);
sem_wait(&sem_empty);
}
pthread_exit(0);
}
void *write_thread(void *data)
{
threadData *thread_data;
thread_data = (threadData *) data;
sem_wait(&sem_full);
slow_write(thread_data->fd, thread_data->buf.buf, thread_data->buf.numBytes);
sem_post(&sem_empty);
pthread_exit(0);
}
So my issue is in what to assign to my threadData variables in main, and my semaphore logic in the read and write threads. I appreciate any help you're able to give
Being a windows guy who does not use file descriptors I might be wrong with the in's and out's but I think this needs to be done in your main in order to setup the threadData structures.
producerData.fd = in;
consumerData.fd = out;
Then declare ONE SINGLE object of type bufType for both structures. Change for example the definition of threadData to
struct threadData {
int fd;
bufType* buf;
};
and in your Main, you write
bufType buffer;
producerData.buf = &buffer;
consumerData.buf = &buffer;
Then both threads will use a common buffer. Otherwise you would be writing to the producerData buffer, but the consumerData buffer will stay empty (and this is where your writer thread is looking for data)
Then you need to change your signalling logic. Right now your program cannot accept input that exceeds BUFFER_SIZE, because your write thread will only write once. There needs to be a loop around it. And then you need some mechanism that signals the writer thread that no more data will be sent. For example you could do this
void *read_thread(void *data)
{
threadData *thread_data;
thread_data = (threadData *) data;
while((thread_data->buf->numBytes = slow_read(thread_data->fd, thread_data->buf->buf, BUFFER_SIZE)) > 0)
{
sem_post(&sem_full);
sem_wait(&sem_empty);
}
sem_post(&sem_full); // Note that thread_data->buf->numBytes <= 0 now
pthread_exit(0);
}
void *write_thread(void *data)
{
threadData *thread_data;
thread_data = (threadData *) data;
sem_wait(&sem_full);
while (thread_data->buf->numBytes > 0)
{
slow_write(thread_data->fd, thread_data->buf->buf, thread_data->buf->numBytes);
sem_post(&sem_empty);
sem_wait(&sem_full);
}
pthread_exit(0);
}
Hope there are no more errors, did not test solution. But the concept should be what you were asking for.
You could use a common buffer pool, either a circular array or a linked lists. Here is a link to a zip of a Windows example that is similar to what you're asking, using linked lists as part of a inter-thread messaging system to buffer data. Other than the creation of the mutexes, semaphores, and the write thread, the functions are small and simple. mtcopy.zip .

passing a structure to a thread

I want to know how to pass a structure to a thread. I've written an example application where I declare a structure in main and try to pass it to the thread.
Here's my code:
DWORD WINAPI Name1(LPVOID lparam)
{
data x;
x.name[15]="Sarah";
x.DOB="19/10/2007";
fputs(stdout,name,15);
fputs(stdout,DOB,15);
return 0;
}
int main()
{
struct data
{
char name[15];
char DOB[15];
};
HANDLE thread2;
DWORD threadID2;
thread2= CreateThread(NULL,0,Name1,(LPVOID *)data,0,&threadID2);
if(thread2==NULL)
{
cout<<"Couldn't Create Thread:("<<endl;
exit(0);
}
return 0;
}
Unfortunately, I am not getting the hang of passing a structure to a thread :( I would really appreciate it if somebody helped me out.
I tried to change the datatype of the structure to pass it, but, I guess I don't know how to do it.
You are passing a local variable to the thread startup function. Once the variable goes out of scope it will be destroyed. This means it may not exist when the new thread tries to access it. You should either pass by value for integral types or allocate the object in dynamic storage (the heap).
Once the new thread has the pointer to the object it should probably be responsible for destroying it as well. That all depends on how you want to assign and manager ownership of the object.
struct Foo
{
char name[15];
char DOB[15];
};
void Start()
{
Foo *someObject = new Foo();
CreateThread(NULL, 0, threadFunc, (LPVOID *)someObject, 0, &threadID2);
}
DWORD WINAPI threadFunc(void *v)
{
Foo *someObject = static_cast<Foo*>(v);
delete someObject;
return 0;
}
If you want to pass a struct to a thread, you've to get that struct on the heap and not on the stack and pass its address to the thread.
I also fixed a few mistakes... Like string copy, and so on...
I didn't use any typedef, as it appears you're using C++.
struct data{
char name[15];
char DOB[15];
};
DWORD WINAPI Name1(LPVOID lparam)
{
data *x = (data*)lparam;
strcpy(x->name, "Sarah");
strcpy(x->DOB, "19/10/2007");
fputs(stdout, x->name, 15);
fputs(stdout, x->DOB, 15);
HeapFree(GetProcessHeap(), 0, x);
return 0;
}
int main()
{
HANDLE thread2;
DWORD threadID2;
data * x;
x = HeapAlloc(GetProcessHeap(), 0, sizeof(data));
thread2= CreateThread(NULL, 0, Name1, (LPVOID)x, 0, &threadID2);
if(thread2==NULL)
{
cout << "Couldn't Create Thread:(" << endl;
exit(0);
}
return 0;
}

share pointer between processes via shared-memory IPC

I'm trying to share a pointer of defined class between the parent and the forked child through shared memory.
so in parent's main i create the pointer
mydata *p;
Reader::GetInstance()->Read(p, i+1);
pid = fork();
if (pid == -1){
cout << "error on fork"<<endl;
}else if (pid == 0){
cout << "i will fork now" <<endl;
const char * path = "./mydatamanager";
execl (path, "-", (char *)0);
break;
}else {
writer(shmid, p);
}
writer contains this
void writer(int shmid , mydata * p)
{
void *shmaddr;
shmaddr = shmat(shmid, (void *)0, 0);
if((int)shmaddr == -1)
{
perror("Error in attach in writer");
exit(-1);
}
else
{
memcpy( shmaddr, p, sizeof(*p) );
}
}
and my data is
class mydara {
public:
int var1;
int var2;
int var3;
int var4;
int var5;
int var6;
char *var7;
mydata (int v2, int v3,char *v7, int v6){
var2 = v2;
var3 = v3;
var7 =new char[128];
strcpy(var7, v7);
var6 = v6;
var4 = 0;
var5 = 0;
}
};
and in the mydatamanager i get this pointer this way
void reader(int shmid, mydata *& p)
{
cout << "in reader" << endl;
void *shmaddr;
//sleep(3);
shmaddr = shmat(shmid, (void *)0, SHM_RDONLY|0644);
if((int)shmaddr == -1)
{
perror("Error in reader");
exit(-1);
}
else
{
cout << "in else "<< endl;
p = (mydata*) shmaddr;
cout <<"shared memory address is " <<shmaddr <<endl;
cout <<"var5 "<< p->var5<< endl;
cout <<"var2 "<< p->var2<< " match with "<<getpid() << "?" << endl;
cout <<"var3 "<< p->var3<< endl;
cout <<"var4 "<< p->var4<< endl;
cout <<"var7 "<< p->var7<< endl; // the
//shmdt(shmaddr);
}
}
and mydatamanager main :
int main()
{
cout << "in main" <<endl;
int shmid;
shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT|0644);
cout << "in advanced point" <<endl;
sleep(1);
mydata * p;
reader (shmid, p);
cout << p->var7 <<endl;
return 0;
}
the results are always 0.
how can i share this pointer through the parent and the child and where is the fault in my code?
Hi i had a IPC task some weeks ago and finally decided to use boost.
http://blog.wolfgang-vogl.com/?p=528
http://www.boost.org/doc/libs/1_36_0/doc/html/interprocess/synchronization_mechanisms.html#interprocess.synchronization_mechanisms.semaphores.semaphores_interprocess_semaphores
First of all, you are not synchronising anything. So how do you know which runs first, the reader or the writer. Memory is bound to be zero in a newly allocated block, so hence you get zero as a result.
Any shared memory must ensure that the reader doesn't read until the writer has completed (at least part of) the writing process, at the very least.
Beware of sharing classes - you must not use virtual functions, as that will almost certainly do something ohterthan what you expect (crash, most likely, but other options are available, none of them particularly pleasant)
The simplest way to handle your problem is to create a semaphore in the parent process before the fork, have the child process try to acquire it before the read (instead of doing a sleep) and the parent process release it after the write.
First, here's functions to create, destroy, and retreive the id of the semaphore:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int create_semaphore(const char *path, char id, int count){
key_t k = ftok(path, id);
semid = semget(k, 1, IPC_CREAT | IPC_EXCL | 0600);
semctl(semid, 0, SET_VAL, count);
return semid;
}
int destroy_semaphore(int semid){
semctl(semid, 0, IPC_RMID, 0);
}
int get_semaphore(const char *path, char id){
key_t k = ftok(path, id);
semid = semget(k, 1, 0600);
return semid;
}
Now we need a function to acquire it, and another one to release it:
void acquire_semaphore(int semid){
sembuf op;
op.sem_num = O;
op.sem_op = -1;
op.sem_flg = 0;
semop(semid,&op,1);
}
void release_semaphore(int semid){
sembuf op;
op.sem_num = 0;
op.sem_op = 1;
op.sem_flg = 0;
semop(semid,&op,1);
}
With these boilerplate functions in place, you should be able to synchronize your processes.
So, you will need to provide a path and a unique id (in the form of a simple character) to create and identify your semaphore. If you already used ftok to create your shared memory id (shmid), you should understand the idea. Otherwise, just make sure that both values are the same within both processes.
In your writer code, put the following line:
semid = create_semaphore(argv[0], 'S', 0);
right before the pid = fork(); line, to create and acquire the semaphore at the same time.
Add the line:
release_semaphore(semid);
after the writer(shmid, mydata); instruction to release the semaphore. You will also need to declare semid somewhere in scope. I used the writer program path to create the semaphore, which is good practice to ensure that no other process has already used our path. The only catch is that you need to make sure that reader will use that same path. You can hardcode that value somewhere in reader's code, or better yet, pass it from writer in the execl parameters (left as an exercise).
Assuming that path is known in reader, all is left to do is to acquire the the semaphore likeso:
semid = get_semaphore(path, 'S');
acquire_semaphore(semid);
destroy_semaphore(semid);
before the line reader(shmid, mydata); in the main function of reader.
As other posts have said, sharing class instances through a shared memory segment is usually a very bad idea. It is much safer
to pass simple struct data, and reconstruct your object on the reader side (look up serialization and marshalling on the net for more information).
Ask if you have problems with this (untested) code.
Merry Christmas!