Logs thread in C - c

Here is my problem ! I want to make a log Thread. But the buffer between the writer thread and the reader thread don't seems to work.
The buffer is in the:
typedef struct{
char *bufLog;
pthread_mutex_t mutex;
} sLog;
sLog* globalLog;
The reader thread read permanently the buffer and print what is it inside on the screen.
void* lireLog(void *param_l){
while(1){
pthread_mutex_lock(&(globalLog->mutex));
if(strlen(globalLog->bufLog) > 0)
printf("Log: %s\n", globalLog->bufLog);
pthread_mutex_unlock(&globalLog->mutex);
}
return 0;
}
And the writer thread write into the buffer.
void *otherThread(){
while(1){
ecrireLog("salut");
}
}
void* ecrireLog(char *text){
pthread_mutex_lock(&(globalLog->mutex));
memcpy(globalLog->bufLog, text, strlen(text));
pthread_mutex_unlock(&(globalLog->mutex));
return 0;
}
And there is the main()
int main(int argc, char *argv[]){
globalLog->bufLog = (char*) malloc(sizeof(char*)*255);
res = pthread_mutex_init(&(globalLog->mutex), NULL);
if (res) {fprintf(stderr, "create %s", strerror(res));exit(1);}
//creation du thread log
res = pthread_create(&log_t, NULL, lireLog, NULL);
if (res) {fprintf(stderr, "create %s", strerror(res));exit(1);}
res = pthread_create(&other_t, NULL, otherThread, NULL);
if (res) {fprintf(stderr, "create %s", strerror(res));exit(1);}
pthread_join(log_t, NULL);
pthread_join(other_t, NULL);
}
Thanks ! :)

Related

Segmentation fault due to file descriptor in multi threaded client

I have created a client-server file sharing system with multi threading. The client code is working correctly for a single client. When I increase the number of threads in client, segmentation fault is occurred in server code.
When I executed the code on gdb, it shows the error segmentation fault occurred, no such file or directory. Is this because of the threads sharing file descriptor? How to resolve the segmentation fault?
----------edit-----------
I considered all your suggestions. Most of the errors are resolved, but when I try to send a >10mb file, some send-recv call does not execute fully while sending it out with threads(It works fine with a single thread). I believe this is the reason memory leakage is happening and ultimately results in segmentation fault(file pointers not closed). The same is happening in gdb.
How to resolve this send receive blocking error?
client code
#include <time.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<string.h>
#include<stdio.h>
#include <stdlib.h>
#include<pthread.h>
#include <semaphore.h>
#define PORT 8029
#define SIZE 1024
#define SERVER_ADDR "192.168.43.158" //"10.15.36.112"
//defining number of threads
struct ser_data
{
int sockfd;
int n;
};
void *client_req(void * data){
// printf("inside thread\n");
//sleep(1);
int s,c,n,read_size,r;
//login_id and password of the user
//array to choose file names randomly
//char f_name[20][20]={"f0.txt","f1.txt","f2.txt","f3.txt","f4.txt","f5.txt","f6.txt","f7.txt","f8.txt","f9.txt","f10.txt\0","f11.txt\0","f12.txt\0" ,"f13.txt\0","f14.txt\0","f15.txt\0","f16.txt\0","f17.txt\0","f18.txt","f19.txt"};
//socket address for client and server
//used for generation of random no
time_t t;
struct sockaddr_in cli,serv;
FILE *f;
char fname[SIZE]="file_cli/";
char f_name[SIZE];
char login_id[21], pswd[21], choice[2];
//msg_cli_rec= message recieved form server
char msg_cli_rec[SIZE];
//msg_cli_send =message sent by client
char msg_cli_send[SIZE];
time_t start, stop;
int brk=0;
start = time(NULL);
s=socket(AF_INET,SOCK_STREAM,0);
bzero((char*)&serv,sizeof(cli));
cli.sin_family=AF_INET;
cli.sin_port=htons(PORT);
cli.sin_addr.s_addr = inet_addr(SERVER_ADDR);
connect(s,(struct sockaddr*)&cli,sizeof(cli));
//printf("\nConnected with server");
strcpy(choice, "1");
/*msg_cli_rec = (char *) malloc(1000* sizeof(char));
msg_cli_send = (char *) malloc(1000* sizeof(char));*/
//if user wants to login
if(strcmp(choice,"1")==0)
{
strcpy(login_id, "prach");
send(s, login_id, sizeof(login_id), 0);
strcpy(pswd, "prach");
send(s, pswd, sizeof(pswd), 0);
}
//making default choice download 1
do {
strcpy(choice, "1\0");
strcpy(msg_cli_send, choice);
//send(s, choice, sizeof(choice), 0);
send(s,msg_cli_send,sizeof(msg_cli_send),0);
//random number generation
srand((unsigned) time(NULL));
//r=((unsigned)rand()*(i++))%20;
r=15;
if(strcmp(choice,"1")==0)
{
/*if(recv(s, msg_cli_rec, sizeof(msg_cli_rec), 0))
{
//if((strcmp("end",msg_cli_rec))==0)break;
printf("\n%s", msg_cli_rec);
}*/
/*printf("\nEnter the file name you want:");
scanf("%s", msg_cli_send);*/
// to select file name with index of the random number
sprintf(f_name,"file (%d).txt",r);
strcpy(msg_cli_send, "");
strcpy(msg_cli_send,f_name);
// printf("\n%s",msg_cli_send);
// printf("\n rand =%d\n", r );
send(s,msg_cli_send,sizeof(msg_cli_send),0);
// printf("\nThe received file content is:");
//receiving the file names
f = fopen(strcat(fname,f_name),"w");
bzero( msg_cli_rec, sizeof(msg_cli_rec));
while((recv(s, msg_cli_rec, sizeof(msg_cli_rec), 0)> 0)&&(*msg_cli_rec!='\0'))
{//fflush(stdout);
if((strcmp("quit",msg_cli_rec))==0)break;
fprintf(f, "%s", msg_cli_rec);
//printf("\n%s", msg_cli_rec);
bzero( msg_cli_rec, sizeof(msg_cli_rec));
}
// printf("File recieved");
fclose(f);
strcpy(fname,"\0" );
//sem_post(&sem);
}
stop = time(NULL);
// printf("\n%s\n", ctime(&stop));
//printf("%ld", (stop-start));
//set the timer to 300 seconds
}while(*choice == '1' && (stop-start)<10);
//tell the server that we are done with sending files
strcpy(choice, "0");
send(s, choice, sizeof(choice), 0);
printf("%ld\n", (stop-start) );
/* free(msg_cli_rec);
free(msg_cli_send);*/
close(s);
//pthread_exit(NULL);
}
int main()
{
int N_Threads=2, count =0;
struct ser_data data;
/*while(N_Threads<=2)
{
pthread_t t;
pthread_create( &t , NULL , client_req , NULL);
N_Threads++;
if ( ! pthread_detach(t) )
printf("Thread detached successfully !!!\n");
//pthread_join(t, NULL);
}*/
while(count != N_Threads){
pthread_t handle;
count = count+1;
data.sockfd = count;
if(pthread_create(&handle, NULL, client_req,(void *)&data)<0)
error("Error creating thread");
else
printf("Thread allocation successful for fd: %d\n",data.sockfd);
}
pthread_exit(NULL);
}
server code
#include <time.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<string.h>
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<dirent.h>
#include <mysql/mysql.h>
#include <semaphore.h>
#define PORT 8029
#define SIZE 1024
#define QUERY_SIZE 200
#define N_Threads 5
#define SERV_ADDR "192.168.43.158"
clock_t start, stop;
//login id and password of the user
int file_id=1;
/*Database variables*/
MYSQL *db_conn;
char *db_server = "localhost";
char *db_user = "root";
char *db_password = "root";
char *database = "file_db";
//for synchronization while accessing the db
sem_t sem;
/* A function which generates the and returns login query statement*/
char* query_login(char *query, char *login_id, char *pswd)
{
//generating query
strcpy(query,"SELECT * FROM user_info WHERE user_id='");
strcat(query, login_id);
strcat(query, "' AND pswd='");
strcat(query, pswd);
strcat(query, "'");
return query;
}
/* A function which generates and returns the register query statement*/
char* query_register(char *query, char *login_id, char *pswd)
{
strcpy(query, "INSERT INTO user_info VALUES ( '");
strcat(query, login_id);
strcat(query, "', '");
strcat(query, pswd);
strcat(query, "' )");
return query;
}
void *connect_client(void *socket)
{ int sock=*(int*)socket;
printf("\nFD %d",sock);
char msg_c_r[SIZE], msg_s_s[SIZE];
//for the choice given to the user to login or register
char choice='0';
char msg_serv_send[SIZE],msg_serv_rec[SIZE];
char msg_cli_rec[SIZE];
char fpath[SIZE] = "file_serv/";
char fname[SIZE];
int read_size;
int num_fields=0;
char * line = NULL;
size_t len = 0;
ssize_t read;
MYSQL_ROW row;
MYSQL_RES *db_res;
char login_id[21], pswd[21];
FILE *f;
FILE *fc;
char name[SIZE];
char query1[SIZE];
char query[QUERY_SIZE];
/*locking the database for mutual exclusion*/
//sem_wait(&sem);
//executing a query
choice = '1';
strcpy(query, "\0");
switch(choice)
{
//1 = login
case '1':
/*to find the login id and password of the user*/
bzero(login_id, sizeof(login_id));
recv(sock, login_id, sizeof(login_id), 0);
bzero(pswd, sizeof(pswd));
recv(sock, pswd, sizeof(pswd), 0);
printf("The login id is: %s\nThe Password is: %s\n", login_id, pswd);
//lock for accessing db in mutual exclusion
sem_wait(&sem);
query_login(query, login_id, pswd);
//checking the details given by client
if (mysql_query(db_conn, query)!=0) {
fprintf(stderr, "%s\n", mysql_error(db_conn));
}
strcpy(query, "\0");
strcat(query,"select * from user_info where user_id='");
strcat(query,login_id);
strcat(query,"'");
mysql_query(db_conn, query);
db_res = mysql_store_result(db_conn);
row = mysql_fetch_row(db_res);
if (row!=0) {
//send(sock,"T",sizeof("T"),0);
printf("\nT");
}
//freeing the result variable so it can be used further
mysql_free_result(db_res);
//release lock
sem_post(&sem);
break;
}//switch case
/*send(sock, "\nPlease enter your choice \n 1- File Download \n 2-File Upload\n 3-Rating\n", sizeof("\nPlease enter your choice \n 1- File Download \n 2-File Upload\n 3-Rating\n"), 0);*/
int nu=1;
do{
bzero(msg_serv_rec,sizeof(msg_serv_rec));
if(recv(sock, msg_serv_rec,sizeof(msg_serv_rec), 0)>0)
{
choice = msg_serv_rec ? *msg_serv_rec : '0';
printf("\n choice = %c\n", choice);
strcpy(query, "\0");
//printf("Client's choice is file Download\n" );
/*Sending File to the client line by line
checking the database connection*/
if(choice == '1'){
/*if(mysql_query(db_conn, "SELECT name FROM file_info")==0)
{
db_res = mysql_store_result(db_conn);
num_fields = mysql_num_fields(db_res);
if(num_fields>0)
{
while ((row = mysql_fetch_row(db_res)))
{
for(int i = 0; i < num_fields; i++)
{
char *fname1=row[i] ? row[i] : "NULL";
strcat(name,fname1);
strcat(name, "\n");
//send(sock,name,sizeof(name),0);
//printf("\n%s",name);
}
}
//sending list of all files to client
send(sock,name,sizeof(name),0);*/
/*emptying the name!!
strcpy(name, "");*/
//freeing the result variable so it can be used further
/*mysql_free_result(db_res);
sem_post(&sem);*/
bzero(msg_serv_rec,sizeof(msg_serv_rec));
if(recv(sock, msg_serv_rec,sizeof(msg_serv_rec), 0)>0)
{//which file recieved
printf("%s\n", msg_serv_rec );
// sem_wait(&sem);
f = fopen(strcat(fpath, msg_serv_rec),"r");
while(fgets(msg_serv_send, sizeof(msg_serv_send), f) !=NULL)
{
if((*msg_serv_send!=EOF || *msg_serv_send!='\n'))
{
send(sock, msg_serv_send, sizeof(msg_serv_send), 0);
//printf("\n%s", msg_serv_send);
}
else
break;
}
send(sock,"quit",sizeof("quit"),0);
fclose(f);
strcpy(fpath, "file_serv/");
//sem_post(&sem);
printf("\nFile sent to the client\n");
}
}
else if (choice == '0')
break;
strcpy(msg_serv_rec, "");
//stop = clock();
//time(NULL);
}
else
{
choice = '0';
}
}while ( choice != 'f' && choice != '0');
nu++;
/* unblocking the semaphores to allow other threads to access*/
//sem_post(&sem);
if(read_size == 0)
{
puts("\nClient disconnected\n");
fflush(stdout);
}
/*else if(read_size == -1)
{perror("recv failed");}
fclose(f);*/
close(sock);
pthread_exit(NULL);
}
int main()
{ int s,n,i, clilen;
int c;
int newsockfd;
int *new_sock;
start = clock();
//pthread_t handle;
struct sockaddr_in cli,serv;//socket address for client and server
MYSQL_ROW row;
MYSQL_RES *db_res;
//initializing the semaphore
sem_init(&sem, 0, 1);
//synchronization in DB
sem_wait(&sem);
/*Database connectivity*/
db_conn = mysql_init(NULL);
/* Connect to database */
if (!mysql_real_connect(db_conn, db_server, db_user, db_password, database, 0, NULL, 0)) {
fprintf(stderr, "%s\n", mysql_error(db_conn));
exit(1);
}
/* send SQL query */
if (mysql_query(db_conn, "show tables")) {
fprintf(stderr, "%s\n", mysql_error(db_conn));
exit(1);
}
db_res = mysql_use_result(db_conn);
/* output table name */
printf("MySQL Tables in mysql database:\n");
while ((row = mysql_fetch_row(db_res)) != NULL)
printf("%s \n", row[0]);
//freeing the result variable so it can be used further
mysql_free_result(db_res);
sem_post(&sem);
//Server socket
s=socket(AF_INET,SOCK_STREAM,0);
bzero((char*)&serv,sizeof(serv));
serv.sin_family=AF_INET;
serv.sin_port=htons(PORT);
serv.sin_addr.s_addr=inet_addr( SERV_ADDR);//"10.15.36.112");
/*printf("\nServer is waiting for client to respond");
i=0*/
//accept the incomming connections from client
bind(s,(struct sockaddr *)&serv,sizeof(serv));
printf("\nAddress bind successful");
listen(s,3000);//4 is the limit of the number of outstanding connections
n=sizeof(cli);
/*
i=0;
//accept the incomming connections from client
while( (c = accept(s, (struct sockaddr *)&cli, (socklen_t*)&n))) //&& (stop-start)<300 )
{ puts("Connection accepted\n");
pthread_t t;
printf("sock =%d\n", c);
if( pthread_create( &t , NULL , connect_client , (void*) c) < 0)
{
perror("could not create thread");
return 1;
}
i++;
/*Now detach the thread ,When a detached thread terminates, its resources are
automatically released back to the system without the need for
another thread to join with the terminated thread.*/
/* if ( ! pthread_detach(t) )
printf("Thread detached successfully !!!\n");
puts("Handler assigned");
stop = clock();
}*/
clilen=sizeof(cli);
while(newsockfd = accept(s, (struct sockaddr *) &cli, &clilen))
{
if(newsockfd < 0)
error("ERROR on accept");
else{
pthread_t handle;
new_sock = malloc(1);
*new_sock = newsockfd;
if(pthread_create(&handle, NULL,connect_client ,(void *)new_sock)<0)
error("Error creating thread");
else
printf("Thread fd: %d\n",newsockfd);
if ( ! pthread_detach(handle) )
printf("Thread detached successfully !!!\n");
}
}
/* close database connection */
mysql_free_result(db_res);
mysql_close(db_conn);
close(s);
/*destroying the mutex */
sem_destroy(&sem);
return 0;
}

Basic posix thread argument passing issue

I am trying to get into the world of threads and am having some trouble. The code below works every once in a while but seems to be completely random. Giving it the same input keeps giving me different results and I am quite confused.
Sometimes PrintHello() prints out the arguments and other times it prints garbage and sometimes it just segfaults.
#define NUM_THREADS 5
char *prompt = "% ";
struct thread_data{
int thread_id;
//int sum;
char *message;
};
void *PrintHello(void *threadarg)
{
struct thread_data *local_data;
local_data = (struct thread_data *) threadarg;
int taskid = local_data->thread_id;
const char *arguments = local_data->message;
fprintf(stderr, "Hello World! It's me, thread %s!\n", arguments);
pthread_exit(NULL);
}
PrintHello() is where I think the issue is.
int main()
{
int pid;
//int child_pid;
char line[81];
char *token;
char *separator = " \t\n";
char **args;
char **args2;
char *hp;
char *cp;
char *ofile;
int i;
int j, h, t, rc;
args = malloc(80 * sizeof(char *));
args2 = malloc(80 * sizeof(char *));
signal(SIGINT, SIG_IGN);
while (1) {
fprintf(stderr, "%s", prompt);
fflush(stderr);
if (fgets(line, 80, stdin) == NULL)
break;
/* get rid of the '\n' from fgets */
if (line[strlen(line) - 1] == '\n'){
line[strlen(line) - 1] = '\0';
}
// split up the line
i = 0;
while (1) {
token = strtok((i == 0) ? line : NULL, separator);
if (token == NULL)
break;
args[i++] = token;
}
args[i] = NULL;
ofile = args[i-1];
printf("%s\n", ofile);
The stuff above this is just tokenizing the input and works fine.
struct thread_data thread_data_array[i];
pthread_t threads[i];
for(t=0; t<i; t++){
thread_data_array[t].thread_id = t;
thread_data_array[t].message = args[t];
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)&thread_data_array[t]);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
}
}
There are several issues with your code, but I'll focus on the key ones that affect stability.
You're not checking the return values of malloc(). If the return value is NULL, it means the operation failed, and you have to either re-try, or start cleaning up all dynamically allocated memory from malloc(), calloc(), strdup(), etc, and finish up with your program gracefully. Attempting to dereference NULL (ie: use the pointer from the failed memory allocation call) will crash your program.
Your program doesn't account for zero valid arguments provided (ie: just hitting ENTER at the prompt. Change ALL newline instances to '\0', and continue.
Also, count the number of tokens you've discovered. Good practise, and helps you check if no valid input was found.
Consider reading up on starting threads in a detached state versus a joinable state. The biggest problem in your code is that you start all the threads, and then your while loop immediately executes again, and re-assigns new values to the thread[] array. Also, the same argument is passed to them while still in use (thread_data_array[t]), and you have no mutexes to protect them. Also, if your program's main() exits early, then all running threads get killed off immediately, and don't get to finish.
You should pthread_join() on joinable threads to ensure you wait until they complete before you proceed.
You provide no way to exit the program without either using CTRL+C or crashing it. Not a good idea.
Note that the threads don't necessarily execute in the order you created them, though they luckily did in this case. You'll need to learn about barriers, condition variables (condvars) and mutexes to do more advanced synchronization handling.
You're missing a lot of important header files. Surprised your code compiled.
Learn how to debug your code with gdb. In this case, I compiled it via gcc test.c -lpthread -O0 -ggdb, then stepped through the code via the "next" n command after starting it in gdb with run. It makes your life a lot easier.
Updated Code Listing
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#define NUM_THREADS 5
#define BUF_LEN (80)
char *prompt = "% ";
struct thread_data{
int thread_id;
//int sum;
char *message;
};
void *PrintHello(void *threadarg)
{
struct thread_data *local_data;
local_data = (struct thread_data *) threadarg;
int taskid = local_data->thread_id;
const char *arguments = local_data->message;
fprintf(stderr, "Hello World! It's me, thread %s!\n", arguments);
pthread_exit(NULL);
}
int main()
{
int pid;
//int child_pid;
char line[81];
char *token;
char *separator = " \t\n";
char **args;
char **args2;
char *hp;
char *cp;
char *ofile;
int i;
int j, h, t, rc;
args = malloc(BUF_LEN * sizeof(char *)); // ISSUE: Can fail. Check return value.
args2 = malloc(BUF_LEN * sizeof(char *)); // ISSUE: Can fail.
signal(SIGINT, SIG_IGN);
while (1)
{
fprintf(stderr, "%s", prompt);
fflush(stderr);
if (fgets(line, BUF_LEN, stdin) == NULL)
{
break;
}
/* get rid of the '\n' from fgets */
/*
if (line[strlen(line) - 1] == '\n'){
line[strlen(line) - 1] = '\0';
}
*/
for ( t = 0; t < BUF_LEN; t++ )
{
if ( line[t] == '\n' )
{
line[t] = '\0';
}
}
// split up the line
i = 0;
int numTokens = 0;
while (1) {
token = strtok((i == 0) ? line : NULL, separator);
if (token == NULL)
{
break;
}
args[i++] = token;
numTokens++;
}
// Abort if zero tokens found.
if ( numTokens == 0 )
{
continue;
}
// Exit if input is "quit"
if ( strcasecmp(line, "quit") == 0 )
{
break;
}
args[i] = NULL;
ofile = args[i-1];
printf("%s\n", ofile);
struct thread_data thread_data_array[i];
pthread_t threads[i];
for(t=0; t<i; t++)
{
thread_data_array[t].thread_id = t;
thread_data_array[t].message = args[t];
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)&thread_data_array[t]);
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
// Wait for threads to complete work.
for(t=0; t<i; t++)
{
pthread_join(threads[t], NULL);
}
}
}
Sample Run
%
%
%
% Hello world. This is a test
test
Hello World! It's me, thread test!
Hello World! It's me, thread a!
Hello World! It's me, thread is!
Hello World! It's me, thread This!
Hello World! It's me, thread world.!
Hello World! It's me, thread Hello!
%
% 1 2 3
3
Hello World! It's me, thread 3!
Hello World! It's me, thread 2!
Hello World! It's me, thread 1!
% QUit

Producer, consumer POSIX

I am trying to write simple producer consumer app using C POSIX semaphores.
Consumer:
int memoryID;
struct wrapper *memory;
int main(int argc, char **argv) {
srand(time(NULL));
key_t sharedMemoryKey = ftok(".",MEMORY_KEY);
if(sharedMemoryKey==-1)
{
perror("ftok():");
exit(1);
}
memoryID=shmget(sharedMemoryKey,sizeof(struct wrapper),0);
if(memoryID==-1)
{
perror("shmget(): ");
exit(1);
}
memory = shmat(memoryID,NULL,0);
if(memory== (void*)-1)
{
perror("shmat():");
exit(1);
}
while(1)
{
int r = rand();
sem_wait(&memory->full);
sem_wait(&memory->mutex);
int n;
sem_getvalue(&memory->full,&n);
printf("Removed item: %d",(memory->array)[n]);
usleep(1000000);
sem_post(&memory->mutex);
sem_post(&memory->empty);
}
}
Producer:
int memoryID;
struct wrapper *memory;
int rc;
void atexit_function() {
rc = shmctl(memoryID, IPC_RMID, NULL);
rc = shmdt(memory);
}
int main(int argc, char **argv) {
atexit(atexit_function);
//creating key for shared memory
srand(time(NULL));
key_t sharedMemoryKey = ftok(".", MEMORY_KEY);
if (sharedMemoryKey == -1) {
perror("ftok():");
exit(1);
}
memoryID = shmget(sharedMemoryKey, sizeof(struct wrapper), IPC_CREAT | 0600);
if (memoryID == -1) {
perror("shmget():");
exit(1);
}
memory = shmat(memoryID, NULL, 0);
if (memory == (void *) -1) {
perror("shmat():");
exit(1);
}
//initialization
memset(&memory->array, 0, sizeof(memory->array));
sem_init(&memory->mutex, 1, 1);
sem_init(&memory->empty, 1, SIZE_OF_ARRAY);
sem_init(&memory->full, 1, 0);
if (memoryID == -1) {
perror("shmget(): ");
exit(1);
}
while(1)
{
int r = rand();
sem_wait(&memory->empty);
sem_wait(&memory->mutex);
int n;
sem_getvalue(&memory->full,&n);
printf("Adding task\t Value:%d\tNumber of tasks waiting:%d \n",r,n);
(memory->array)[n]=r;
usleep(1000000);
sem_post(&memory->mutex);
sem_post(&memory->full);
}
}
common.h:
#define MEMORY_KEY 5
#define SIZE_OF_ARRAY 10
struct wrapper
{
int array[SIZE_OF_ARRAY];
sem_t empty;
sem_t mutex;
sem_t full;
};
What is happening:
Producer is starting successfully
Producer is successfully adding elements to table and printing them out Quickly after starting producer,
I am starting consumer Consumer does not take element from
array even once
Producer fills up the array and is waiting
I do not really see where is the problem. I suspect that the problem is the implementation not the algorithm cause the algorithm is taken from wikipedia Link
Your consumer works fine. It's just not flushing to stdout. Do as nos suggested by putting a \n at the end of your consumer printf call. You can also see it working by just waiting longer. Your producer will start producing again after the consumer has executed a few iterations.

Communicate with zeromq with protobuf serialized messages

I am unable to receive message serialized in protobuf over ZeroMQ sockets using C.
I have serialized message entered by client and send this buffer to server using s_send() function defined in zhelpers.h. The server code is same test code bundled with zeromq package as an examples.
Here is my client side:
#include "amessage.pb-c.h"
#include "zhelpers.h"
int main (void)
{
AMessage msg = AMESSAGE__INIT; // AMessage
void *buf; // Buffer to store serialized data
unsigned len;
printf ("Connecting to server...\n");
void *context = zmq_ctx_new ();
void *requester = zmq_socket (context, ZMQ_REQ);
char buffer[256] = "";
printf("[client] :");
scanf("%s", buffer );
msg.csmsg = buffer;
len = amessage__get_packed_size(&msg);
buf = malloc(len);
printf("[client]: pack msg len : %d\n ", len);
printf("Sent msg : %d\n", buf);
amessage__pack(&msg,buf);
s_send(requester, buf);
zmq_close (requester);
zmq_ctx_destroy (context);
return 0;
}
And server side:
#include "zhelpers.h"
#include <pthread.h>
#include <stdlib.h>
#include "amessage.pb-c.h"
#define MAX_MSG_SIZE 256
static size_t read_buffer (unsigned max_length, unsigned char *out)
{
size_t cur_len = 0, nread;
uint8_t c;
while ((nread=fread(out + cur_len, 1, max_length - cur_len, stdin)) != 0)
{
cur_len += nread;
if (cur_len == max_length)
{
fprintf(stderr, "[server]: max message length exceeded\n");
exit(1);
}
}
return cur_len;
}
static void * worker_routine (void *context)
{
AMessage *msg;
uint8_t buf[MAX_MSG_SIZE];
char buffer[256];
// Socket to talk to dispatcher
void *receiver = zmq_socket (context, ZMQ_REP);
zmq_connect (receiver, "inproc://workers");
while (1) {
uint8_t *string = s_recv (receiver);
if(string == 0)
printf("[server]: Error: In receiving msg.\n");
else
{
size_t msg_len = read_buffer (MAX_MSG_SIZE, string);
printf("[server]: client msg len is: %d.\n", msg_len);
msg = amessage__unpack(NULL, msg_len, string);
if (msg == NULL)
{
fprintf(stderr, "[server]: error unpacking incoming message\n");
exit(1);
}
printf ("[client]: %s \n", msg->csmsg);
}
amessage__free_unpacked(msg, NULL);
free (string);
// Do some 'work'
sleep (1);
}
zmq_close (receiver);
return NULL;
}
int main (void)
{
void *context = zmq_ctx_new ();
void *clients = zmq_socket (context, ZMQ_ROUTER);
zmq_bind (clients, "tcp://*:5555");
void *workers = zmq_socket (context, ZMQ_DEALER);
zmq_bind (workers, "inproc://workers");
// Launch pool of worker threads
int thread_nbr;
for (thread_nbr = 0; thread_nbr < 5; thread_nbr++) {
pthread_t worker;
pthread_create (&worker, NULL, worker_routine, context);
}
// Connect work threads to client threads via a queue proxy
zmq_proxy (clients, workers, NULL);
zmq_close (clients);
zmq_close (workers);
zmq_ctx_destroy (context);
return 0;
}
Any idea what I am doing wrong?
You are using s_send() which expects a C string as an argument, and calls strlen() to determine its size. However, protocol buffers data is binary data, and may contain null bytes anywhere in the message.
Instead use zmq_send() and give the length of the message to the zmq_msg_init_size() function.

Capture a child process's stdout with libuv

I'm using libuv. I've read http://nikhilm.github.com/uvbook/processes.html and still cannot work out how to capture the stdout of a child process so that it is available in the parent (but not in place of the parent's stdin).
My code is currently:
#include <stdio.h>
#include <stdlib.h>
#include "../../libuv/include/uv.h"
uv_loop_t *loop;
uv_process_t child_req;
uv_process_options_t options;
uv_pipe_t apipe;
void on_child_exit(uv_process_t *req, int exit_status, int term_signal) {
fprintf(stderr, "Process exited with status %d, signal %d\n", exit_status, term_signal);
uv_close((uv_handle_t*) req, NULL);
}
uv_buf_t alloc_buffer(uv_handle_t *handle, size_t len) {
printf("alloc_buffer called\n");
uv_buf_t buf;
buf.base = malloc(len);
buf.len = len;
return buf;
}
void read_apipe(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) {
printf("read %li bytes from the child process\n", nread);
}
int main(int argc, char *argv[]) {
printf("spawn_test\n");
loop = uv_default_loop();
char* args[3];
args[0] = "dummy";
args[1] = NULL;
args[2] = NULL;
uv_pipe_init(loop, &apipe, 0);
uv_pipe_open(&apipe, 0);
options.stdio_count = 3;
uv_stdio_container_t child_stdio[3];
child_stdio[0].flags = UV_IGNORE;
child_stdio[1].flags = UV_INHERIT_STREAM;
child_stdio[1].data.stream = (uv_stream_t *) &apipe;
child_stdio[2].flags = UV_IGNORE;
options.stdio = child_stdio;
options.exit_cb = on_child_exit;
options.file = args[0];
options.args = args;
uv_read_start((uv_stream_t*)&apipe, alloc_buffer, read_apipe);
if (uv_spawn(loop, &child_req, options)) {
fprintf(stderr, "%s\n", uv_strerror(uv_last_error(loop)));
return 1;
}
return uv_run(loop, UV_RUN_DEFAULT);
}
dummy.c:
#include <unistd.h>
#include <stdio.h>
int main() {
printf("child starting\n");
sleep(1);
printf("child running\n");
sleep(2);
printf("child ending\n");
return 0;
}
I have the nagging feeling that I do not quite understand the point of libuv's pipes yet.
I've found the solution:
I had the wrong flags, they should have been UV_CREATE_PIPE | UV_READABLE_PIPE not UV_INHERIT_STREAM.
I needed to call uv_read_start after uv_spawn. I assume that there's no chance of data loss, as uv_run has not yet been called.
The above two fixes showed all the output from dummy to arriving at once, rather than in three lumps (as it does on the command line). An fflush in dummy.c fixed this.
spawn_test:
#include <stdio.h>
#include <stdlib.h>
#include "../../libuv/include/uv.h"
uv_loop_t *loop;
uv_process_t child_req;
uv_process_options_t options;
uv_pipe_t apipe;
void on_child_exit(uv_process_t *req, int exit_status, int term_signal) {
fprintf(stderr, "Process exited with status %d, signal %d\n", exit_status, term_signal);
uv_close((uv_handle_t*) req, NULL);
}
uv_buf_t alloc_buffer(uv_handle_t *handle, size_t len) {
printf("alloc_buffer called, requesting a %lu byte buffer\n");
uv_buf_t buf;
buf.base = malloc(len);
buf.len = len;
return buf;
}
void read_apipe(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) {
printf("read %li bytes in a %lu byte buffer\n", nread, buf.len);
if (nread + 1 > buf.len) return;
buf.base[nread] = '\0'; // turn it into a cstring
printf("read: |%s|", buf.base);
}
int main(int argc, char *argv[]) {
printf("spawn_test\n");
loop = uv_default_loop();
char* args[3];
args[0] = "dummy";
args[1] = NULL;
args[2] = NULL;
uv_pipe_init(loop, &apipe, 0);
uv_pipe_open(&apipe, 0);
options.stdio_count = 3;
uv_stdio_container_t child_stdio[3];
child_stdio[0].flags = UV_IGNORE;
child_stdio[1].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
child_stdio[1].data.stream = (uv_stream_t *) &apipe;
child_stdio[2].flags = UV_IGNORE;
options.stdio = child_stdio;
options.exit_cb = on_child_exit;
options.file = args[0];
options.args = args;
if (uv_spawn(loop, &child_req, options)) {
fprintf(stderr, "%s\n", uv_strerror(uv_last_error(loop)));
return 1;
}
uv_read_start((uv_stream_t*)&apipe, alloc_buffer, read_apipe);
return uv_run(loop, UV_RUN_DEFAULT);
}
dummy.c:
#include <unistd.h>
#include <stdio.h>
int main() {
printf("child starting\n");
fflush(stdout);
sleep(1);
printf("child running\n");
fflush(stdout);
sleep(2);
printf("child ending\n");
fflush(stdout);
return 0;
}
See how they do it in the libuv unit test libuv/test/test-stdio-over-pipes.c:
Don't call uv_pipe_open
Flags for child's stdin: UV_CREATE_PIPE | UV_READABLE_PIPE
Flags for child's stdout and stderr: UV_CREATE_PIPE | UV_WRITABLE_PIPE
There is also an issue on Windows, where uv_spawn might return zero even though it encountered an error, and in those cases, you need to check process.spawn_error, which only exists on Windows.

Resources