ahhhh, thank you VEERYYYY much, I was already loosing my mind. And I'm new to C programming so I'm still at war with pointers. Now it seams so logical and easy but I wouldn't never figure it out by myself. btw. now it's working nice :)
Printable View
ahhhh, thank you VEERYYYY much, I was already loosing my mind. And I'm new to C programming so I'm still at war with pointers. Now it seams so logical and easy but I wouldn't never figure it out by myself. btw. now it's working nice :)
I must thank you again, you made my day :)
Eh I did it again , I nested the struct to add locking mechanism, and now it's jumping again by 0x190 instead just 20 bytes.
Output at the moment:Code:#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define KEY (5679)
typedef struct
{
int x, y, xo, yo, id;
}command[20], *command_ptr;
typedef struct _tcommand
{
int lock;
command comm;
}tcommand;
main ()
{
int shmid, shmkeyid, i, size;
command *tuio_cmd;
tcommand *tcomm;
size = sizeof( *tcomm);
shmid = shmget (KEY, size, 0666 | IPC_CREAT);
if (shmid != -1)
{
tcomm = shmat (shmid, NULL, 0);
if (tcomm != (void *) -1)
{
tuio_cmd = &(*tcomm).comm;
printf ("Memory tcomm@:%X tcom->comm@: %X, size of struct:%d\n\n", (int) tcomm, (int)tcomm->comm,(int) tuio_cmd,size);
tuio_cmd[4]->xo = 1; //Set old X just to test if block
for( i=0; i<20; i++ )
{
command_ptr p = &(*tuio_cmd)[i]; // <--- pointer p points to memory location of i'th member of tuio_cmd array
printf ("Memory tuio_cmd[%d]@: %p\n",i,p->x);
// if (tuio_cmd[i]->xo) // Check if there is old x and y, it's enaugh to check just one
// printf ("num:%d,X:%d,Y:%d,Xo:%d,Yo:%d,Id:%d\n", i,tuio_cmd[i]->x,tuio_cmd[i]->y, tuio_cmd[i]->xo, tuio_cmd[i]->yo, tuio_cmd[i]->id);
// else // We get just one point coordinates
// printf ("X:%d,Y:%d,Id:%d\n", tuio_cmd[i]->x,tuio_cmd[i]->y,tuio_cmd[i]->id);
}
if (shmdt (tcomm) == -1)
{
fprintf (stderr, "shmdt failed\n");
exit (EXIT_FAILURE);
}
if (shmctl (shmid, IPC_RMID, 0) == -1)
{
fprintf (stderr, "shmctl(IPC_RMID) failed\n");
exit (EXIT_FAILURE);
}
}
else fprintf(stdout,"error attaching memory\n");
}
else fprintf(stdout,"error in allocating shm\n");
return 0;
}
Memory tcomm@:B7F81000 tcom->comm@: B7F81004,tuio: B7F81004, size of struct:404
Memory tuio_cmd[0]@: (nil)
Memory tuio_cmd[1]@: (nil)
... (repeating)
I have tried every possible combination that crossed my mind .. from (*tuio_cmd)[i]->x to tuio_cmd[i].x with and without pointers, even as its shown here I added p as pointer to the memory. Obviously without success.
And I see that the memory allocation for the tuio_cmd is good (start + 4 bytes for int of lock). I really don't understand how the !@$!#% is done.
If someone is willing to give me a hand again ok. If not, it doesn't matter anymore, as I don't want to exploit the good will of the ppl.
[edit]
Oh finally, I think I got it ..
Output:Code:command_ptr p = &((*tuio_cmd)[i]); // <--- pointer p points to memory location of i'th member of tuio_cmd array
Memory tcomm@:B7F99000 tcom->comm@: B7F99004,tuio: B7F99004, size of struct:404
Memory tuio_cmd[0]@: 0xb7f99004
Memory tuio_cmd[1]@: 0xb7f99018
Memory tuio_cmd[2]@: 0xb7f9902c
Memory tuio_cmd[3]@: 0xb7f99040
Memory tuio_cmd[4]@: 0xb7f99054
....
First......take a break ;)
When you come back, remove that "[20]" out of your typedef - that's making *my* head hurt!
Fix the rest based on that. Post yours progress here if you hit a wall.Code:typedef struct command_
{
int x, y, xo, yo, id;
} command;
typedef struct tcommand_
{
int lock;
command comms[20];
} tcommand;
gg
Eheh I know .. that's hurting my head too, but as you see I'm having really hard time with it,
finally I made it. But now I would like to optimize a little and beautify the code. It's just too ugly this way. About that [20] eheh I tried that few times before .. when I was stuck at the first issue, I'll try again and see If I'll have any luck. If you see anything else that could be "fixed" or typed more simple plz. let me know.
In my code editor, I turn off real tab characters and use nothing but spaces (editor inserts spaces when I hit tab). That will help keep your posted code looking the same as it does in your editor.
My personal rule-of-thumb is never to "hide a pointer" inside a typedef, like "command_ptr" - which also "hides" an array-20 inside itself.......(head starting to hurt)....
The code is a bit more "self-documenting" that way as well. Consider
>> anything else that could be "fixed"Code:command comms[20];
vs
command comm; // command is really "array-20"
Probably need to add proper memory synchronization to your shared memory accesses.
How many producers?
How many consumers?
How do consumers know when something has been produced?
How to producers know consumers are ready to consume?
What is the policy for dealing with more "production" than the consumers can handle?
gg
Ok listening your suggestions, I have come to following:
Now I have warrning: assignment from incompatible pointer type @34 line tuio_cmd[0] = &(*tcomm).comm;Code:#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define KEY (5679)
typedef struct
{
int x, y, xo, yo, id;
}command; // command is really "array-20"
typedef struct _tcommand
{
int lock;
command comm[20];
}tcommand;
main ()
{
int shmid, shmkeyid, i, size;
command *tuio_cmd[20],*p;
tcommand *tcomm;
size = sizeof( *tcomm);
shmid = shmget (KEY, size, 0666 | IPC_CREAT);
if (shmid != -1)
{
tcomm = shmat (shmid, NULL, 0);
if (tcomm != (void *) -1)
{
tuio_cmd[0] = &(*tcomm).comm;
// printf ("Memory tcomm@:%X tcom->comm@: %X,tuio: %X, size of struct:%d\n\n", (int) tcomm, (int)tcomm->comm,(int) tuio_cmd,size);
while(1)
{
if(((*tcomm).lock)==1)
{
for( i=0; i<20; i++ )
{
p = &((*tuio_cmd)[i]); // <--- pointer p points to memory location of i'th member of tuio_cmd array
if (p->xo) // Check if there is old x and y, it's enaugh to check just one
printf ("num:%d,X:%d,Y:%d,Xo:%d,Yo:%d,Id:%d\n", i,p->x,p->y, p->xo, p->yo, p->id);
else // We got just one point coordinates
printf ("num:%d,X:%d,Y:%d,Id:%d\n",i, p->x,p->y,p->id);
}
((*tcomm).lock)=0;
}
}
if (shmdt (tcomm) == -1)
{
fprintf (stderr, "shmdt failed\n");
exit (EXIT_FAILURE);
}
if (shmctl (shmid, IPC_RMID, 0) == -1)
{
fprintf (stderr, "shmctl(IPC_RMID) failed\n");
exit (EXIT_FAILURE);
}
}
else fprintf(stdout,"error attaching memory\n");
}
else fprintf(stdout,"error in allocating shm\n");
return 0;
}
About consumer/producers .. producer is actually python script, so I'm not afraid that it can
send more that the C part can handle. About synchronization, I have added lock int just for that.
I'm still not sure this is optimized code .. so if you see something else that could be "adjusted" plz share.. and thnx for assisting me. :)
Ps. offcourse everything is working well now. (as far I can see for now)
>> command *tuio_cmd[20]
That is a fixed size array of pointers to command. Not what you want.
Here is everything simplified, types, code, and tabs:
So you got some TODO's there one you're comfortable with the code.Code:#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define KEY (5679)
typedef struct
{
int x, y, xo, yo, id;
} command;
typedef struct
{
int lock;
command comm[20];
} tcommand;
int main()
{
int shmid, i;
tcommand *tcomm;
shmid = shmget(KEY, sizeof(*tcomm), 0666 | IPC_CREAT);
if (shmid == -1)
{
fprintf(stderr,"error in allocating shm\n");
exit(EXIT_FAILURE);
}//if
tcomm = shmat(shmid, NULL, 0);
if (tcomm == (void*)-1)
{
fprintf(stderr,"error attaching memory\n");
exit(EXIT_FAILURE);
}//if
while (1)
{
// TODO: use real synchronization
if (tcomm->lock == 1)
{
for (i = 0; i < 20; ++i)
{
command *p = &(tcomm->comm[i]);
// Check if there is old x and y, it's enough to check just one
if (p->xo)
printf("num:%d,X:%d,Y:%d,Xo:%d,Yo:%d,Id:%d\n",
i, p->x, p->y, p->xo, p->yo, p->id);
else
printf("num:%d,X:%d,Y:%d,Id:%d\n",
i, p->x, p->y, p->id);
}//for
tcomm->lock = 0;
}//if
// TODO - don't use 100% CPU
// TODO - some way to stop
}//while
if (shmdt(tcomm) == -1)
{
fprintf(stderr, "shmdt failed\n");
exit(EXIT_FAILURE);
}//if
if (shmctl(shmid, IPC_RMID, 0) == -1)
{
fprintf(stderr, "shmctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}//if
return 0;
}//main
gg
Ok I added the semaphore locking, and exit out the loop with previous lock. Only TODO remaining is dont use 100% of cpu, what do you mean by that ?
here is the code:
Another question, I'm thinking on using this in threaded program, so I'm not sure if semaphore approach isCode:#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#define KEY (5679)
typedef struct
{
int x, y, xo, yo, id;
} command;
typedef struct
{
int lock;
command comm[20];
} tcommand;
void seminit()
{
int id;
union semun {
int val;
struct semid_ds *buf;
ushort * array;
} argument;
argument.val = 0;
id = semget(KEY, 1, 0666 | IPC_CREAT);
if(id < 0)
{
fprintf(stderr, "Unable to obtain semaphore.\n");
exit(0);
}
if( semctl(id, 0, SETVAL, argument) < 0)
{
fprintf( stderr, "Cannot set semaphore value.\n");
}
else
{
fprintf(stderr, "Semaphore %d initialized.\n", KEY);
}
}
int main()
{
int shmid, i;
tcommand *tcomm;
shmid = shmget(KEY, sizeof(*tcomm), 0666 | IPC_CREAT);
if (shmid == -1)
{
fprintf(stderr,"error in allocating shm\n");
exit(EXIT_FAILURE);
}//if
tcomm = shmat(shmid, NULL, 0);
if (tcomm == (void*)-1)
{
fprintf(stderr,"error attaching memory\n");
exit(EXIT_FAILURE);
}//if
seminit(); //Init the semaphore
int id;
struct sembuf operations[1];
int retval;
id = semget(KEY, 1, 0666); //semaphores and shared memory have separate key spaces, so one can safely use the same key for each.
if(id < 0)
{
fprintf(stderr, "Cannot find semaphore, exiting.\n");
exit(0);
}
do
{
operations[0].sem_num = 0;
operations[0].sem_op = -1;
operations[0].sem_flg = 0;
retval = semop(id, operations, 1);
for (i = 0; i < 20; ++i)
{
command *p = &(tcomm->comm[i]);
// Check if there is old x and y, it's enough to check just one
if (p->xo)
printf("num:%d,X:%d,Y:%d,Xo:%d,Yo:%d,Id:%d\n",
i, p->x, p->y, p->xo, p->yo, p->id);
else
printf("num:%d,X:%d,Y:%d,Id:%d\n",
i, p->x, p->y, p->id);
}//for
}while (!tcomm->lock);
if (shmdt(tcomm) == -1)
{
fprintf(stderr, "shmdt failed\n");
exit(EXIT_FAILURE);
}//if
if (shmctl(shmid, IPC_RMID, 0) == -1)
{
fprintf(stderr, "shmctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}//if
return 0;
}//main
wise, as it's blocking and waiting for signal.And one more thing, why is now sitting and waiting for second release of semaphore .. I added while after do, so it should exit as soon the condition is satisfied.
[edit]
I got it why it was entering in the loop for second time, it was the other side (python script) which had the glitch.. now Is working well.And about the thread .. I'm still able to release the semaphore with
signal from main thread so that wouldn't have to be the problem I think.
>> ... don't use 100% of cpu, what do you mean by that?
Before, there was just a while(1) loop that did nothing but if() and printf(). The OS and CPU will gladly run that loop as fast as it can. When there's no work to be done, you should be blocked in the OS somewhere.
>> Ok I added the semaphore
You are on the right track!
>> I'm not sure [of] semaphore approach
There are still a few things to consider. Right now your loop will block at semop() until the semaphore value is non-zero. At this point, we're waiting for the python script to populate the data. Once the data is populated in shared memory, the python script increments the semaphore - which in turn allows the semop() call to to return. This works great if you only need to send one parcel of data.
But what if we want to send multiple tcommand's? How does the python script know that it's ok to write more data? In other words, how does it know that we've completed reading everything it just sent us?
There are several ways to tackle this depending on what you want to do. Just for an example, let's say they you wanted your producer (python script) to block until the produced data has been consumed - meaning no data should be lost, it should all be consumed.
>> I'm thinking on using this in threaded programCode:semaphore s = 0;
producer()
{
while()
{
wait until s == 0
produce tcommand
set s = 2
}
}
consumer()
{
while()
{
s -= 1 // blocking semop
consume tcommand
s -= 1 // should not block since producer set s = 2 (assumes single consumer)
}
}
What we've been talking about so far is IPC over shared memory between two processes. But in reality, it's not much different from two threads communicating over a malloc'd chunk of memory :)
gg
That worked really nice, good logic .. I must learn to think like that. I tried different approach, which I found in other producer/consumer C examples. But they weren't appropriate for my case as I'm using python, and It's hard to synchronize it. About the thread .. I didn't mean that I'm going to share the malloced memory over the multiple threads, I'm using one thread just to get and parse the commands received over shared memory. Anyway as I'm going to release the code (after I finish it) as GPL, I'm going to share here also, since there could be someone else who could benefit from this. It's a nice way to connect python and C over low latency solution :)
So the C part in question looks now like this:
And the python part :Code:operations[0].sem_num = 0;
operations[0].sem_op = -1;
operations[0].sem_flg = 0;
retval = semop(semid, operations, 1);
for (i = 0; i < MAXBLOBS; ++i)
{
command *p = &(tcomm->comm[i]);
// Check for blob Id, If there isn't any skip, it's void
if (p->id)
{
// Check if there is old x and y, it's enough to check just one
if (p->xo)
printf("num:%d,X:%d,Y:%d,Xo:%d,Yo:%d,Id:%d\n",
i, p->x, p->y, p->xo, p->yo, p->id);
else
printf("num:%d,X:%d,Y:%d,Id:%d\n",
i, p->x, p->y, p->id);
}//if
}//for
operations[0].sem_num = 0;
operations[0].sem_op = -1;
operations[0].sem_flg = 0;
retval = semop(semid, operations, 1);
PS. Thnx for the hints and guide trough this voyage in C programming.Code:#!/usr/bin/env python
import shm
import ctypes
class tuio(ctypes.Structure):
_fields_ = [
('x',ctypes.c_int),
('y',ctypes.c_int),
('xo',ctypes.c_int),
('yo',ctypes.c_int),
('id',ctypes.c_int)
]
class nested(ctypes.Structure):
_fields_=[
('lock',ctypes.c_int),
('comm',tuio*20)
]
x=100 #some test data
y=123 #same here
key = 5679
i=0 #send just array [0]
mem = shm.memory(shm.getshmid(key))
sem = shm.semaphore(shm.getsemid(key))
sem.setval(0) #set the semaphore = 0
mem.attach()
tuio_cmd = nested()
tuio_cmd.comm[i].x=x
tuio_cmd.comm[i].y=y
tuio_cmd.comm[i].id=1
tuio_cmd.lock=1 #sets the lock to 1 and the main C program exits on this
sem.Z() #wait for semaphore == 0
mem.write(tuio_cmd) #write to the memory
sem.setval(2) #set the semaphore s=2