I am newbie using gpsd with C. I implemented my first client which uses gps_stream function. If I understood correctly, it is like a pub/sub function that you can read gps data using gps_read. I want to retrieve the data as soon as it is available. The only way I found is to decrease the time on the gps_waiting function. I wonder if there is a way to not use the gps_waiting function and retrieve as soon as possible. Here below is my code.
int runGpsStreamClient() {
int rc;
int count = 0;
clock_t t;
struct gps_data_t gps_data;
t = clock();
if ((rc = gps_open("localhost", "2947", &gps_data)) == -1) {
printf("code: %d, reason: %s\n", rc, gps_errstr(rc));
return EXIT_FAILURE;
}
get_metric(t, "gps_open");
t = clock();
gps_stream(&gps_data, WATCH_ENABLE | WATCH_JSON, NULL);
get_metric(t, "gps_stream");
while (count < 60) {
/* wait for 0.1 second to receive data */
if (gps_waiting(&gps_data, 100000)) {
t = clock();
int rc = gps_read(&gps_data);
get_metric(t, "gps_read");
/* read data */
if (rc == -1) {
printf("error occurred reading gps data. code: %d, reason: %s\n", rc, gps_errstr(rc));
} else {
/* Display data from the GPS receiver. */
double lat = gps_data.fix.latitude;
double lon = gps_data.fix.longitude;
double alt = gps_data.fix.altitude;
double speed = gps_data.fix.speed;
double climb = gps_data.fix.climb;
time_t seconds = (time_t) gps_data.fix.time;
int status = gps_data.status;
int mode = gps_data.fix.mode;
printf("status[%d], ", status);
printf("mode[%d], ", mode);
printf("latitude[%f], ", lat);
printf("longitude[%f], ", lon);
printf("altitude[%f], ", alt);
printf("speed[%f], ", speed);
printf("v speed[%f], ", climb);
printf("Time[%s].", ctime(&seconds));
if ((status == STATUS_FIX)
&& (mode == MODE_2D || mode == MODE_3D)
&& !isnan(lat) && !isnan(lon)) {
printf(" GPS data OK.\n");
} else {
printf(" GPS data NOK.\n");
}
}
} else {
printf("counter[%d]. Timeout to retrieve data from gpsd. Maybe increase gps_waiting.\n", count);
}
count++;
}
/* When you are done... */
gps_stream(&gps_data, WATCH_DISABLE, NULL);
gps_close(&gps_data);
return EXIT_SUCCESS;
}
Thanks,
Felipe
From the gpsd documents (emphasis mine)
gps_waiting() can be used to check whether there is new data from the daemon. The second argument is the maximum amount of time to wait (in microseconds) on input before returning. It returns true if there is input waiting, false on timeout (no data waiting) or error condition. When using the socket export, this function is a convenience wrapper around a select(2) call...
gps_waiting(&gps_data, t) will block up to t microseconds if there is no new data. As soon as new data is received from the GPS, gps_waiting should return. If no new data is received, the function will timeout and return after t microseconds.
Getting a faster data rate will be dependent on how fast your GPS is outputting data. Merely decreasing the second parameter of gps_waiting will give you the illusion of faster data rates, but if you check the function's return value, you'll see that all you've done is cause the function to time out quicker.
Related
SHORT: My problem is that the following function which sum the content of a given array in a given range, doesn't take the same execution time for the same task as the parent if called from a child. And by same I mean similar values. Because after some tests, the differences is for about a ~40% more for the child to execute.
LONG: I'm studying computer science and I'm working on the final project of a course. The problem is to sum all the cells of an int array by n processes distributing the workload. then confront it to a single calculation made by parent. The point is to demonstrate that, with big arrays, multiple process can reduce the execution time.
However, the sum of all children's times is always more than the parent's even with 50milions data.
Following just the function and the struct I use to pass results.
typedef struct cResults{
double time;
int result;
}cResult;
cResult arraySum(int start, int length, int* dataset)
{
/*Time unit to calculate the computation time*/
clock_t tic, toc = 0;
cResult chunk = {.result = 0, .time =0};
tic = clock(); // Start measure time
for (int i = start; i < start + length; i++)
{
chunk.result += dataset[i];
}
toc = clock(); // Stop measure time
chunk.time = ((double) (toc - tic))/ CLOCKS_PER_SEC;
printf("B: start at: %d, length: %d, sum: %d, in: %f\n", start, length, chunk.result, chunk.time); //! DEBUG
return chunk;
}
WHAT I'VE TRIED SO FAR:
Since the array is dynamically allocated, I've thought that it could be a bottleneck on the memory access. However, this question (Malloc returns same address in parent and child process after fork) lifted all doubt that even if heap allocated, they are not the same, but a copy of the array.
I've double checked that the parent will sum correctly and only once the elapsed time communicated by all the children, and then added the print() statement just to read and sum manually on the terminal all the results. And again, all checks.
I've tried moving the function call by parent from before to after all children were done, but no changes, then I've tried make the parent sleep() right after fork() (this was counterproductive for the purpose of the project but just to make sure) for avoiding resource queue.
The random numbers in the array are produced in a repeatable way through a seed, so I've tried same datasets that of course will give almost identical outputs, and again times will change slightly yet maintaining the single execution faster.
Ultimately I've tried to fork a single child and make it calculate the same range as the parent (so all the array). The time is on average 45% slower on children.
Surely I'm missing a simple thing but i run out of ideas... please be patient I'm learning by my self at my best.
UPDATE 1:
Since I've been asked for a full program, I've refactored mine. However, whereas the project required a single source file I've removed all of non regarding parts of our issue, hence it should be lighter. Unfortunately the frame you'll see that handle the pipe communications is a bit complex I'm afraid but it serve for other purpose that has been removed yet essential to make this works. I do hope it won't be a problem.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
/* ----- PROTOTYPES ----- */
#define MIN 5 // Least number of process and threads
#define MAX 10 // Maximum number of process and threads
#define MSGSIZE 4 // Size of pipe messages
/* =================
*PIPE MESSAGES*
sum = Sum from the next given start to the next given roof.
end = End process
tmr = Return the computation time measured by the process
================= */
/// #brief Struct containing proces id (pid), the result and it's pipe file descriptors
struct process{
pid_t pid;
long int result;
bool done;
double time;
int fd[2];
};
/// #brief Struct that containts the result of the computation
typedef struct cResults{
double time;
long int result;
}cResult;
/// #brief W = write, R = read
enum PIPECONTROLLER{
R = 0,
W = 1
};
/* ----- PROTOTYPES ----- */
cResult arraySum(int start, int length, int* dataset);
int main()
{
/* =================
*USER DEFINED*
================= */
int dataLength = 50000000; // Set the length of the dataset
int nProcess = 1; // How many child process do you want
unsigned int seed = 1; // Change the randomization seed of the data
// System
int* data;
cResult chunk; // Used for storing temporary computational values
// Task related
int taskLenght;
int remainder;
// Pipe related
char pipeMSG[MSGSIZE];
int msgCheck = 1;
/// #brief Processes dashboard
struct process processes[MAX + 1] = { {.pid = 0, .result = 0, .done = false, .time = 0} };
data = malloc(sizeof(int) * dataLength);
srand(seed);
for (int i = 0; i < dataLength; i++)
{
/*Random population between 0-100*/
data[i] = rand() % 100;
}
chunk = arraySum(0, dataLength, data);
processes[nProcess + 1].result = chunk.result;
processes[nProcess + 1].time = chunk.time;
printf("\nCHECK SUM: %ld\n", chunk.result);// ! Debug
#pragma region "START PROCESSES"
/*Calculate how to separate the overhead for the processes*/
taskLenght = dataLength / nProcess;
remainder = dataLength % nProcess;
pid_t myPid = 0;
int startPoint = 0;
processes[nProcess + 1 ].pid = getpid();
/*Open child to parent pipe*/
if (pipe(processes[nProcess + 1 ].fd) == -1)
{
printf("Failed to open pipe on parent\n");
return 1;
}
for (int i = 0; i < nProcess; i++)
{
/*Open new parent to child pipe*/
if (pipe(processes[i].fd) == -1)
{
printf("Failed to open pipe on parent\n");
return 1;
}
myPid = fork();
switch (myPid)
{
case -1: // Error on fork
printf("An error occured while forking the %d process.\n", i);
return 1;
break;
case 0: // Child case
/*Record pid in the dashboard*/
processes[i].pid = getpid();
/*Handle the pipes descriptors*/
close(processes[i].fd[W]);
close(processes[nProcess + 1 ].fd[R]);
i = nProcess;
break;
default: // Parent case
/* Record the pid process into the dashrboard and increment the starting for the next*/
processes[i].pid = myPid;
startPoint += taskLenght;
/*Handle the pipes descriptors*/
close(processes[i].fd[R]);
break;
}
}
/*=========== CHILD PROCESS HANDLER ===========*/
if(myPid == 0)
{
int myID;
bool keepAlive = true;
for(myID = 0; myID < nProcess; myID++)
{
if (processes[myID].pid == getpid())
{
break;
}
}
/*Calculate first iteration of the sum*/
cResult temp = arraySum(startPoint, taskLenght, data);
chunk.result = temp.result;
chunk.time = temp.time;
while(keepAlive)
{
/*Comunicate the id of the process*/
if (write(processes[nProcess + 1 ].fd[W], &myID, sizeof(int)) < 0)
{
printf("An error occured from the process %d while sending message to parent\n", getpid());
return 1;
}
/*Communicate the result of the operation*/
if (write(processes[nProcess + 1 ].fd[W], &chunk.result, sizeof(int)) < 0)
{
printf("An error occured from the process %d while sending message to parent\n", getpid());
return 1;
}
/*Communicate the time elapsed for the operation*/
if (write(processes[nProcess + 1 ].fd[W], &chunk.time, sizeof(double)) < 0)
{
printf("An error occured from the process %d while sending message to parent\n", getpid());
return 1;
}
/*Waits for further instruction*/
msgCheck = read(processes[myID].fd[R], pipeMSG, MSGSIZE);
if(msgCheck < 0)
{
printf("An error occured from the process %d while reading message from parent\n", getpid());
return 1;
}
/*Sum command*/
if(!strcmp(pipeMSG, "sum"))
{
msgCheck = read(processes[myID].fd[R], &startPoint, sizeof(int));
if(msgCheck < 0)
{
printf("An error occured from the process %d while reading message from parent\n", getpid());
return 1;
}
msgCheck = read(processes[myID].fd[R], &taskLenght, sizeof(int));
if(msgCheck < 0)
{
printf("An error occured from the process %d while reading message from parent\n", getpid());
return 1;
}
/*Calculate second iteration for the remaining part*/
temp = arraySum(startPoint, taskLenght, data);
chunk.result += temp.result;
chunk.time += temp.time;
}
/*Close command*/
if(!strcmp(pipeMSG, "end"))
{
keepAlive = false;
}
}
free(data);
close(processes[myID].fd[R]);
exit(0);
}
/*=========== PARENT PROCESS HANDLER ===========*/
if(myPid != 0)
{
/*Close descriptor for writing on main pipe.*/
close(processes[nProcess + 1 ].fd[W]);
int targetProcess = nProcess + 1; // Target self
bool onGoing = true;
chunk.result = 0;
chunk.time = 0;
while(onGoing)
{
/*Listen from processes if someone ended the task*/
msgCheck = read(processes[nProcess + 1 ].fd[R], &targetProcess, sizeof(int));
if(msgCheck < 0)
{
printf("An error occured from the process %d while reading message from parent\n", getpid());
return 1;
}
/*Get result from child process*/
msgCheck = read(processes[nProcess + 1 ].fd[R], &processes[targetProcess].result, sizeof(int));
if(msgCheck < 0)
{
printf("An error occured from the process %d while reading message from parent\n", getpid());
return 1;
}
/*Get elapsed time from child process*/
msgCheck = read(processes[nProcess + 1 ].fd[R], &processes[targetProcess].time, sizeof(double));
if(msgCheck < 0)
{
printf("An error occured from the process %d while reading message from parent\n", getpid());
return 1;
}
processes[targetProcess].done = true;
/*Check if remainder to start new task*/
if(remainder != 0)
{
startPoint = taskLenght * nProcess;
processes[targetProcess].done = false;
if (write(processes[targetProcess].fd[W], "sum", MSGSIZE) < 0)
{
printf("An error occured from the process %d while sending message to parent\n", getpid());
return 1;
}
if (write(processes[targetProcess].fd[W], &startPoint, sizeof(int)) < 0)
{
printf("An error occured from the process %d while sending message to parent\n", getpid());
return 1;
}
if (write(processes[targetProcess].fd[W], &remainder, sizeof(int)) < 0)
{
printf("An error occured from the process %d while sending message to parent\n", getpid());
return 1;
}
remainder = 0; //Avoid looping task
}
/*Check for pending response and process final result*/
for (int i = 0; i < nProcess; i++)
{
if(processes[i].done)
{
chunk.result += processes[i].result;
chunk.time += processes[i].time;
onGoing = false;
continue;
}
onGoing = true;
/*Reset total calculations*/
chunk.result = 0;
chunk.time = 0;
break;
}
/*Reset to self target*/
targetProcess = nProcess + 1;
}
printf("Parent calculated: %ld in = %fs\n", processes[nProcess + 1].result, processes[nProcess + 1].time); //! Debug
printf("Processes calculated: %ld in = %fs\n", chunk.result, chunk.time); //! Debug
}
}
cResult arraySum(int start, int length, int* dataset)
{
/*Time unit to calculate the computation time*/
clock_t tic, toc = 0;
cResult chunk = {.result = 0, .time =0};
tic = clock(); // Start measure time
for (int i = start; i < start + length; i++)
{
chunk.result += dataset[i];
}
toc = clock(); // Stop measure time
chunk.time = ((double) (toc - tic))/ CLOCKS_PER_SEC;
printf("start at: %d, length: %d, sum: %ld, in: %f\n", start, length, chunk.result, chunk.time); //! Debug
return chunk;
}
If you want to try this out you'll find in USER DEFINED some variable to play with.
I'll share some of my results, with seed = 1.
LENGTH
PARENT
1 CHILD
5 CHILDREN
10 CHILDREN
1'000
0.000001
0.000002
0.000003
0.000006
100'000
0.000085
0.000107
0.000115
0.000120
10'000'000
0.008693
0.015143
0.016120
0.015982
100'000'000
0.089563
0.148095
0.146698
0.149421
500'000'000
0.669474
0.801828
0.744381
0.816883
As you can see even repeating the task in a single child process in some cases required twice the time.
As ArkadiuszDrabczyk pointed out, it could be a scheduling issue, still why has always to be the child the slowest one?
UPDATE 2:
Since pipe's problems arose, I wrote another source just to exclude these concerns and, of course, the problem remained.
However I wasn't convinced about the deep-copy of the dataset[] array stored on heap hence some research later I found this: What is copy-on-write?. After this new found knowledge, I've added this useless function to be called right before the arraySum() :
void justCheck(int start, int length, int* dataset)
{
for (int i = start; i < start + length; i++)
{
dataset[i] = dataset[i];
}
return;
}
This little snippet managed to level the differences between times. At least now they lay on the same order of magnitude.
Down the results:
LENGTH
PARENT
1 CHILD
5 CHILDREN
10 CHILDREN
1'000
0.000002
0.000001
0.000004
0.000003
100'000
0.000099
0.000110
0.000124
0.000121
10'000'000
0.009496
0.008686
0.009316
0.009248
100'000'000
0.090267
0.092168
0.089862
0.093356
500'000'000
-
-
-
-
Unfortunately this edit rise another problem. With big set of data this function freeze. I know this isn't the right way to force the COW so... Any suggestions?
SHORT: Turns out that in order to prove the thesis of the project I was using the wrong approach. Summing all of the clock times taken by each processes and comparing to the single one is like trying to prove that baking 4 pieces of bread in a row takes less than baking all simultaneously counting the oven time instead of watching my watch. I should have measured the wall time instead of clock time.
LONG: That said, regarding why the same function called by only one child takes more time than parent: As I said in my 2nd update I've managed to trim time to a more plausible value forcing the copy-on-write of used heap on child memory page before calling the actual calculating function. So after several experiments, turns out it's aleatory. Sometimes it's faster, sometimes is almost equal and sometimes slower. So, I thinks it depends on how the task scheduling works, which I don't have control on it neither know how to.
Talking about the other problem mentioned:
Unfortunately this edit rise another problem. With big set of data this function freeze. I know this isn't the right way to force the COW so... Any suggestions?
Well the point is that forcing COW on each processes means that, according to Algorithms, 4th Edition by Robert Sedgewick and Kevin Wayne, if I can fit ~
256mln INT value in 1GB of memory the problem is the massive devour of memory my program cause. Checking with my system monitor, I could validate that using 500mln values into my array result in almost 2GB of RAM taken. Which once fork it became equal to nProcess + 1.
I thought to answer these question will help posterity.
I am working on threaded TCP socket server for handling multiple socket client connection. Clients can connect and disconnect asynchronously with server, upon connection, the client should send some data in predefined custom packet protocol format.
The protocol has start of frame(SOP) and end of frame (EOP) defined.
I have written a C code such that for each successful client connection, a thread gets created that keeps on receiving the bytes from client in the predefined packet format, the thread has a thread-local state machine because each client can connect asynchronously so the states for each client may be different.
Below is the thread that receives that data from client and maintains a state based on the type of byte received:
static void *receive_handler(void *args) {
struct thread_args *local_args = args;
struct sockaddr_in6 *client_address = local_args->client_address;
//struct itimerval timer_val;
int32_t conn_fd = local_args->conn_fd;
int32_t val_read = 0;
int32_t resp_code = 0;
uint32_t sendBuffLen = 0;
int8_t buffer[BUFFER_SIZE] = { 0 };
uint8_t RetBuff[1024] = { 0 };
int8_t rx_addr_str[INET6_ADDRSTRLEN];
int8_t byte = 0;
int16_t idx = ePacketType;
int16_t packet_len = 0;
int16_t calculated_crc = 0, recv_crc = 0;
uint16_t num_bytes = 0;
memset(rx_addr_str, 0, INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, &(client_address->sin6_addr), rx_addr_str, INET6_ADDRSTRLEN);
printf("\nRx Thread (%d) Created for %s\n", local_args->connection_no, rx_addr_str);
int eState = eStart_Frame;
memcpy(rx_Packet_Info[local_args->connection_no].inet6, rx_addr_str, INET6_ADDRSTRLEN);
//timerclear(&timer_val.it_interval); /* zero interval means no reset of timer */
//timerclear(&timer_val.it_value);
//timer_val.it_value.tv_sec = 10; /* 10 second timeout */
//(void) signal(SIGALRM, state_reset_handler);
while (1) {
if (eState != eChecksum_Verify) {
val_read = -1;
val_read = recv(conn_fd, &byte, sizeof(byte), 0);
debug_printf(INFO, "Amount Read: %d Byte Rxd: 0x%x => 0x%X\n", val_read, (byte & 0xFF), byte);
if (val_read <= 0) {
if (parse_packet("ERR_DISCONNECT", rx_addr_str, local_args->connection_no) < 0) {
debug_printf(ERR, "Error parsing packet: %s\n", strerror(errno));
}
debug_printf(ERR, "May be closed by client %s: %s\n", rx_addr_str, strerror(errno));
debug_printf(ERR, "Exiting Rx Thread: ConnIdx: %d", num_connections);
close(conn_fd);
pthread_exit(NULL);
}
}
switch (eState) {
case eStart_Frame:
debug_printf(DEBG, "Current State: %d\n", eState);
if ((val_read > 0) && (byte & 0xFF) == SOP) {
memset(buffer, 0, BUFFER_SIZE);
val_read = -1;
buffer[eSOP] = (byte & 0xFF);
eState = eFrame_Len;
}
break;
case eFrame_Len: {
static char MSB_Rxd = 0;
debug_printf(DEBG, "Current State: %d\n", eState);
if (val_read > 0) {
if (MSB_Rxd == 0) {
buffer[ePacket_length] = byte;
MSB_Rxd = 1;
}
else {
buffer[ePacket_length + 1] = byte;
eState = eFrame;
num_bytes = 0;
MSB_Rxd = 0;
packet_len = (buffer[ePacket_length] & 0xFF << 8) | (buffer[ePacket_length + 1]);
debug_printf(INFO, "Packet Length: %d : 0x%x 0x%x\n", packet_len,
buffer[ePacket_length], buffer[ePacket_length + 1]);
}
}
}
break;
case eFrame:
debug_printf(DEBG, "Current State: %d\n", eState);
num_bytes++;
buffer[idx] = byte;
if (num_bytes == packet_len) {
eState = eEnd_Frame;
debug_printf(DEBG, "Num bytes: 0x%x\n", num_bytes);
}
else {
debug_printf(ERR, "Num bytes: 0x%x Pkt Len: 0x%x\n", num_bytes, packet_len);
}
idx++;
break;
case eEnd_Frame:
debug_printf(ERR, "Current State: %d val read %d\n", eState, val_read);
if ((val_read > 0) && (byte & 0xFF) == EOP) {
val_read = -1;
eState = eChecksum_Verify;
}
break;
case eChecksum_Verify: {
calculated_crc = crc_16(&buffer[ePacket_length], (num_bytes));
recv_crc = buffer[num_bytes + 1] << 8 | (buffer[num_bytes + 2] & 0xFF);
if (calculated_crc != recv_crc) {
debug_printf(ERR, "CRC Error! CRC do not match!!\n");
debug_printf(ERR, "Calculated CRC: 0x%X\nCRC Rxd: 0x%X\n", calculated_crc, recv_crc);
resp_code = CRC_ERR;
send(conn_fd, &resp_code, sizeof(resp_code), 0);
}
else {
if (rx_Packet_Info[local_args->connection_no].packetUUID != NULL) {
free(rx_Packet_Info[local_args->connection_no].packetUUID);
rx_Packet_Info[local_args->connection_no].packetUUID = NULL;
}
rx_Packet_Info[local_args->connection_no].packetUUID = calloc(buffer[ePacketUUIDLen],
sizeof(uint8_t));
memcpy(rx_Packet_Info[local_args->connection_no].packetUUID, &buffer[ePacketUUID],
buffer[ePacketUUIDLen]);
rx_Packet_Info[local_args->connection_no].packetUUIDlength = buffer[ePacketUUIDLen];
printf("\nRX-Thread-UUID %d: ConnNo: %d\n", buffer[ePacketUUIDLen],
local_args->connection_no);
for (char i = 0; i < buffer[ePacketUUIDLen]; i++) {
printf("0x%x ", rx_Packet_Info[local_args->connection_no].packetUUID[i]);
}
printf("\n");
if (parse_packet(buffer, rx_addr_str, local_args->connection_no) < 0) {
debug_printf(ERR, "Error parsing packet: %s\n", strerror(errno));
}
}
num_bytes = 0;
eState = eStart_Frame;
idx = ePacketType;
}
break;
default:
debug_printf(DEBG, "Invalid State!! Should not come here.\n");
num_bytes = 0;
eState = eStart_Frame;
idx = ePacketType;
break;
}
}
return NULL;
}
My question is how should I reset this state machine if let's say after receiving start of frame the client gets stuck and is not able to send frame length or complete frame till end of frame?
One way I thought is to implement timer callback but I am not sure how should I keep track of state machine of multiple threads.
Can any one please suggest what should I do in this scenario or if I am doing anything wrong?
If I'm parsing the question correctly, you're asking about how to handle gracefully the situation where the connecting client isn't sending data in a timely manner -- i.e. it has sent the first part of a message, but (due to a network problem or a client-side bug or whatever) never sends the rest, leaving your server-side I/O thread blocked inside a recv() call for a long/indefinite time.
If so, the first question to ask is: is this really a problem? If each connection gets its own thread, then having one particular thread/connection blocked shouldn't cause any issues to the other threads, since they all execute independently of each other. So maybe you can just ignore the problem entirely?
However, the more likely answer is that ignoring the problem isn't quite good enough, because of a couple of subsequent problems that aren't easily ignorable: (a) what if too many client connections "freeze up" at the same time? One or two stalled TCP connections/threads isn't a big deal, but if the same problem keeps happening, eventually you'll run out of resources to spawn more threads or TCP connections, and then your server can no longer function. And (b) what if the server process wants to quit now? (i.e. because the server's user has sent it a SIGINT interrupt or similar) If one or more threads are blocked indefinitely, then it is impossible for the server to exit in a timely-and-controlled manner, because the main thread needs to wait for all the TCP threads to exit first before it can clean up its process-wide resources, and any blocked threads will not exit for a long time, if ever.
So, assuming that the problem does need to be addressed, the most reliable way I've found to address it is to never block in recv() (or send()) in the first place. Instead, make sure to put each socket in non-blocking mode, and have the thread's while-loop block only in a select() call instead. Doing it this way makes your state machine a bit more complex (since it will now have to handle partial-sends as well as partial-receives), but the compensating benefit is that the thread is now in better control of its own blocking behavior. In particular, you can tell select() to always return after a certain amount of time, no matter what, and (better yet) you can tell select() to return whenever any of a number of sockets has bytes ready to be read on it. That means that if your main thread wants to exit, it can use a pipe() or socketpair() to send a dummy-byte to each TCP thread, and the TCP thread (which is presumably blocked inside select(), waiting for either data from its client or from the pipe/socketpair socket) will immediately return from select(), see that the main thread has sent it a byte, and respond by exiting immediately.
That should be sufficient -- in my experience it is better not to impose fixed timeouts if you can avoid it, since it's hard to predict what network performance will be like in all cases, and any rule-of-thumb you might come up with (like "a client that doesn't send the whole message in 5 seconds must be broken") is likely to be wrong, and you'll end up with false-positive problems if you try to enforce that rule. Better to just let each client take as long as it wants/needs to, while also having a mechanism by which the main thread can request that a particular client thread exit immediately if/when that becomes necessary (e.g. during server-process shutdown, or if there are too many TCP threads active and you want to prune some of the old/inactive ones before spawning more)
i have the following loop that is supposed to run at a little above 40Hz (24ms between each run). It works great for a couple of second to minutes, but then goes down to 20Hz for no apparent (at least not to me) reason.
I have tried running the code on a onion Omega 2 (that runs openwrt) and a ubuntu laptop with the same result. (the code went down to 25Hz on the omega2, and 20Hz on my laptop)
How can i force it to continue to run at the right speed? I have checked with an oscilloscope on the output, and the send_brk and send_dmx functions seem to run perfectly even when the program is throttled, so i don't think they are the problem.
double t1 = now();
double t2 = now();
while ( 1 ) {
// Attempt receive UDP data
int x = read(sock, &DMX[1], SIZE - 1);
t2 = now();
double dt = t2 - t1;
if(dt < 0.024){
usleep(500);
continue;
}
t1 = t2;
printf("Frame in %f %f/sec\n", dt, 1.0/dt);
if (x < 0) {
if(errno != EAGAIN){
fprintf(stderr, "Error reading from socket %s\n", strerror(errno));
}
}
send_brk();
send_dmx();
}
the functions called are here:
send_brk() sends a serial break that lasts 88us
void send_brk() {
ioctl(fd, TIOCSBRK);
double start = now();
while((now() - start) < 0.000088){
}
ioctl(fd, TIOCCBRK);
}
send_dmx() writes a byte buffer of lenght 512 to the serial port
void send_dmx() {
// setmode(TX);
int n = write(fd, DMX, SIZE);
if(n == -1) {
if (errno != EAGAIN) {
fprintf(stderr, "Error writing to serial %s\n", strerror(errno));
exit(1);
}
}
if (n != SIZE) {
printf("couldn't write full frame =(\n");
}
}
and now() returns the current time in second as a float.
double now() {
struct timeval tv;
gettimeofday(&tv, NULL);
double time = tv.tv_sec;
time = time + (tv.tv_usec / 1000000.0);
return time;
}
I Work with couple of threads. all running as long as an exit_flag is set to false.
I Have specific thread that doesn't recognize the change in the flag, and therefor not ending and freeing up its resources, and i'm trying to understand why.
UPDATE: After debugging a bit with gdb, i can see that given 'enough time' the problematic thread does detects the flag change.
My conclusion from this is that not enough time passes for the thread to detect the change in normal run.
How can i 'delay' my main thread, long enough for all threads to detect the flag change, without having to JOIN them? (the use of exit_flag was in an intention NOT to join the threads, as i don't want to manage all threads id's for that - i'm just detaching each one of them, except the thread that handles input).
I've tried using sleep(5) in close_server() method, after the flag changing, with no luck
Notes:
Other threads that loop on the same flag does terminate succesfully
exit_flag declaration is: static volatile bool exit_flag
All threads are reading the flag, flag value is changed only in close_server() method i have (which does only that)
Data race that may occur when a thread reads the flag just before its changed, doesn't matter to me, as long as in the next iteration of the while loop it will read the correct value.
No error occurs in the thread itself (according to strerr & stdout which are 'clean' from error messages (for the errors i handle in the thread)
Ths situation also occurs even when commenting out the entire while((!exit_flag) && (remain_data > 0)) code block - so this is not a sendfile hanging issure
station_info_t struct:
typedef struct station_info {
int socket_fd;
int station_num;
} station_info_t;
Problematic thread code:
void * station_handler(void * arg_p)
{
status_type_t rs = SUCCESS;
station_info_t * info = (station_info_t *)arg_p;
int remain_data = 0;
int sent_bytes = 0;
int song_fd = 0;
off_t offset = 0;
FILE * fp = NULL;
struct stat file_stat;
/* validate station number for this handler */
if(info->station_num < 0) {
fprintf(stderr, "station_handler() station_num = %d, something's very wrong! exiting\n", info->station_num);
exit(EXIT_FAILURE);
}
/* Open the file to send, and get his stats */
fp = fopen(srv_params.songs_names[info->station_num], "r");
if(NULL == fp) {
close(info->socket_fd);
free(info);
error_and_exit("fopen() failed! errno = ", errno);
}
song_fd = fileno(fp);
if( fstat(song_fd, &file_stat) ) {
close(info->socket_fd);
fclose(fp);
free(info);
error_and_exit("fstat() failed! errno = ", errno);
}
/** Run as long as no exit procedure was initiated */
while( !exit_flag ) {
offset = 0;
remain_data = file_stat.st_size;
while( (!exit_flag) && (remain_data > 0) ) {
sent_bytes = sendfile(info->socket_fd, song_fd, &offset, SEND_BUF);
if(sent_bytes < 0 ) {
error_and_exit("sendfile() failed! errno = ", errno);
}
remain_data = remain_data - sent_bytes;
usleep(USLEEP_TIME);
}
}
printf("Station %d handle exited\n", info->station_num);
/* Free \ close all resources */
close(info->socket_fd);
fclose(fp);
free(info);
return NULL;
}
I'll be glad to get some help.
Thanks guys
Well, as stated by user362924 the main issue is that i don't join the threads in my main thread, therefore not allowing them enough time to exit.
A workaround to the matter, if for some reason one wouldn't want to join all threads and dynamically manage thread id's, is to use sleep command in the end of the main thread, for a couple of seconds.
of course this workaround is not good practice and not recommended (to anyone who gets here by google)
I want to make a code in which Name of User will be asked to input, but in a time limit of 15 seconds. If user cross the limit & failed to input a name(or any string), then code will be terminated & "Time Out" Massage will be display otherwise Name should be saved & "Thanks" massage will be display. I had try like this but it's wrong & not working. Please give me a solution for this.. Thanks.
#include <stdio.h>
#include <time.h>
int timeout ( int seconds )
{
clock_t endwait;
endwait = clock () + seconds * CLOCKS_PER_SEC ;
while (clock() < endwait) {}
return 1;
}
int main ()
{
char name[20];
printf("Enter Username: (in 15 seconds)\n");
printf("Time start now!!!\n");
scanf("%s",name);
if( timeout(5) == 1 ){
printf("Time Out\n");
return 0;
}
printf("Thnaks\n");
return 0;
}
Probably this dummy program might help you:
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#define WAIT 3
int main ()
{
char name[20] = {0}; // in case of single character input
fd_set input_set;
struct timeval timeout;
int ready_for_reading = 0;
int read_bytes = 0;
/* Empty the FD Set */
FD_ZERO(&input_set );
/* Listen to the input descriptor */
FD_SET(STDIN_FILENO, &input_set);
/* Waiting for some seconds */
timeout.tv_sec = WAIT; // WAIT seconds
timeout.tv_usec = 0; // 0 milliseconds
/* Invitation for the user to write something */
printf("Enter Username: (in %d seconds)\n", WAIT);
printf("Time start now!!!\n");
/* Listening for input stream for any activity */
ready_for_reading = select(1, &input_set, NULL, NULL, &timeout);
/* Here, first parameter is number of FDs in the set,
* second is our FD set for reading,
* third is the FD set in which any write activity needs to updated,
* which is not required in this case.
* Fourth is timeout
*/
if (ready_for_reading == -1) {
/* Some error has occured in input */
printf("Unable to read your input\n");
return -1;
}
if (ready_for_reading) {
read_bytes = read(0, name, 19);
if(name[read_bytes-1]=='\n'){
--read_bytes;
name[read_bytes]='\0';
}
if(read_bytes==0){
printf("You just hit enter\n");
} else {
printf("Read, %d bytes from input : %s \n", read_bytes, name);
}
} else {
printf(" %d Seconds are over - no data input \n", WAIT);
}
return 0;
}
Update:
This is now tested code.
Also, I have taken hints from man for select. This manual already contains a code snippet which is being used to read from the terminal and timeout in 5 seconds in case of no activity.
Just a brief explanation in case the code is not well written enough:
We add the input stream (fd = 1) to the FD set.
We initiate select call to listen to this FD set created for
any activity.
In case any activity occurs within the timeout period, that is
read through the read call.
In case there was no activity, timeout occurs.
Hope this helps.
scanf() is not the best function to get an input in a limited time frame.
Instead I would build a specific input function around select() (for managing timeout) and read() (for getting input) system calls.
One thing you have to think about, is that you have a single thread of execution in your program. As such, the timeout function will only be called when the scanf function will be terminated. This is not what you want.
One way to do this task, is to use the select function. It waits for a potentially limited amount of time (your timeout) for availability of input on some file descriptors (stdin for you).