Newsgroup: it.comp.os.linux.development
Titolo: problema server multithread

Ciao a tutti ho un problema con un server multithread che deve gestire
un elenco telefonico. Il server risiede su un pc mentre il client (o i
client) su un altro. Inoltre devo gestire dei permessi per
l'inserimento dei numeri oppure per la sola consultazione dell'elenco.
Ora però quando vado a compilare mi dà 2 errori undefined reference to
receiveThread e undefined reference to pthread_create. Come mai?
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/socket.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <pthread.h>
#define MAX_DIM 1024
#define CODA 3
#define STRUCTR 32
typedef struct {
	char nome[STRUCTR];
	char cognome[STRUCTR];
	char numero[STRUCTR];
	int presenza;
} record;
void*receiveThread(void*param);
int status;
record r;
int ds_sock;				// Descrittore della socket
int main() {
	int fd;				// Descrittore del file
	int conn_s;			// Descrittore della socket in ascolto
	struct sockaddr_in servaddr;
	struct sockaddr client;
	char buff[MAX_DIM];		// Massima dimensione del buffer lettura
	int b;				// Integer per la sys call bind
	int length;
    int chiave_sem;			// Identifica il semaforo
	int id_sem;
	int res;
	int proc_id;
	pthread_t tid;
    void *status;
	// Inizio creazione semaforo
	chiave_sem=50;
	id_sem = semget(chiave_sem,1,IPC_CREAT|IPC_EXCL|0666);
	if(id_sem == -1){
		id_sem = semget(chiave_sem,1,IPC_CREAT|0666);
		semctl(id_sem,IPC_RMID,0);	//Pulisco l'ambiente
		id_sem = semget(chiave_sem,1,IPC_CREAT|IPC_EXCL|0666);
		if(id_sem == -1){
			printf("\nErrore nella creazione del semaforo.");
			exit(-1);
		}
	}
	// Fine creazione semaforo
	res = semctl(id_sem, 0, SETVAL, 1); //inizializzo il semaforo
	if(res == -1){
			printf("\nErrore nella semctl.");
			exit(-1);
		}
	ds_sock = socket(AF_INET, SOCK_STREAM, 0);
	if (ds_sock == -1) exit(0);
	else printf("Socket creata con successo!\n");
	bzero((char*)&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(2500);
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	b = bind(ds_sock, (struct sockaddr *) &servaddr, sizeof(servaddr));
	listen(ds_sock, CODA);
	if (res == -1) {
		printf("Errore nella listen!\n");
		exit(-1);
	}
	signal(SIGCHLD, SIG_IGN);
	fd= open("Rubrica.txt", O_CREAT, 0666);
	if(fd == -1){
		printf("Errore nell'apertura del file\n");
		exit(-1);
	}
	length = sizeof(client);
	while(1) {
		conn_s = accept(ds_sock, (struct sockaddr*)&client, &length);
		res = waitSem(id_sem);
		if(res == -1){
			printf("Errore nella wait.\n");
			exit(-1);
		}
		if (conn_s == -1) exit(0);
		printf("Connessione accettata.\n");
		proc_id = pthread_create(&tid,NULL,receiveThread,(void*)&conn_s);
		if (proc_id) {
			printf("Impossibile creare il thread. Errore: %d\n", proc_id);
			exit(-1);
			}
		}
		pthread_join(tid,&status);
		if(close(ds_sock)<0){
		printf("Errore durante la close.\n");
		exit(-1);
		}
		void*receiveThread(void*param)
		{
		    read(conn_s,buff,MAX_DIM);
			while (strcmp(buff, "quit") !=0) {
				printf("Valore della password inserito dal client:%s\n", buff);
				if (strcmp(buff, "lett") == 0) {
					write(conn_s, "plett", MAX_DIM);
					leggi_record(conn_s);
				}
				else if (strcmp(buff, "scri") == 0) {
					write(conn_s, "pscrit", MAX_DIM);
					scrivi_record(conn_s);
				}
				else write(conn_s, "errore", MAX_DIM);
				read(conn_s,buff,MAX_DIM);
			}
			close(conn_s);
			printf("\nConnessione chiusa.");
			res = signalSem(id_sem);
			if(res == -1){
				printf("\nErrore nella chiamata signal.\n");
			exit(-1);
			}
			return 0;
			pthread_exit((void*)&status);
		}
}
int leggi_record(int ds) {
	int descrittore_file;
	int retfile;
	int ret;
	int risposta;
	record pfile;
	descrittore_file = open("Rubrica.txt", O_RDONLY);
	if (descrittore_file == -1) {
		printf("Errore nella lettura del file\n");
		exit(-1);
	}
	ret = read(ds, &r, sizeof(record));
	if (ret == -1) {
		printf("Errore nella lettura dal client\n");
		exit(-1);
	}
	printf("Nome richiesto: %s\n",r.nome);
	printf("Cognome richiesto: %s\n",r.cognome);
	do {
		retfile = read(descrittore_file, &pfile, sizeof(record));
	} while ((retfile!=0)&&(!((strcmp(pfile.nome, r.nome)==0)&&(strcmp
(pfile.cognome, r.cognome)==0))));
	if (retfile != 0) {
		pfile.presenza = 1;
		risposta = write(ds, &pfile, sizeof(record));
		if (risposta == -1) {
			printf("Errore nell'invio dei dati al client.\n");
			exit(-1);
		}
		else printf("Dati inviati al client.\n");
	}
	else {
		pfile.presenza = 0;
		risposta = write(ds, &pfile, sizeof(record));
		if (risposta == -1) {
			printf("Errore nell'invio dei dati al client.\n");
			exit(-1);
		}
		else printf("Dati inviati al client.\n");
	}
	close(descrittore_file);
	return 0;
}
int scrivi_record(int ds) {
	int descrittore_file;
	int risp;
	descrittore_file = open("Rubrica.txt", O_WRONLY | O_APPEND);
	if (descrittore_file == -1) {
		printf("Impossibile aprire la rubrica\n");
		exit(-1);
	}
	risp = read(ds, &r, sizeof(record));
	if (risp == -1) {
		printf("Impossibile ricevere i dati dall'utente\n");
		exit(-1);
	}
	risp = write(descrittore_file, &r, sizeof(record));
	r.presenza = 1;
	close(descrittore_file);
	risp = write(ds, &r, sizeof(record));
	if (risp == -1) {
		printf("Dati non inviati correttamente\n");
		exit(-1);
	}
	else printf("Dati inviati correttamente\n");
	return 0;
}
int waitSem(int sem_id) {
	//struct sembuf operazione[1] = {{ numero_semaforo,-1,0}};
	struct sembuf oper;
	oper.sem_num = 0;
	oper.sem_op = -1;
	oper.sem_flg = 0;
	return semop(sem_id, &oper, 1);
}
int signalSem(int sem_id) {
	//struct sembuf operazione[1] = {{ numero_semaforo,+1,0}};
	struct sembuf oper;
	oper.sem_num = 0;
	oper.sem_op = +1;
	oper.sem_flg = 0;
	return semop(sem_id, &oper, 1);
}

 receiveThread e undefined reference to pthread_create. Come mai?
Perchï¿œ gli astri non ti sono favorevoli; se lo fossero, ti avrebbero 
ricordato di postare il comando che dai per compilare ;D
Cmq per la pthread_create il motivo ï¿œ che devi dirgli di usare la 
libreria pthread passando "-lpthread" *dopo* i files da compilare,
tipo    "cc (file.c + opzioni varie) ... -lpthread"
Per la receiveThread, invece, sono curioso e chiedo assistenza anch'io:
il problema ï¿œ che in C, a meno che sia cambiato tutto mentre ero 
distratto, le definizioni di funzione non si possono annidare, cioï¿œ non 
puoi definire receiveThread dentro al main e sperare che funzioni; perï¿œ 
il compilatore sembra accettare quella oscenitï¿œ senza problemi, tanto 
che se compilo senza linkare mi produce un file .o
Qualcuno mi sa dire perchï¿œ mai lo accetta?
gcc -Wall -Wextra etc mi dice "definition shadows previous declaration" 
- ma non dovrebbe dare semplicemente errore?
Grazie in anticipo

In effetti è strano, non dovrebbe accettarlo... e così è infatti: dopo
aver aggiustato un paio di cose (tipo aver definito i prototipi delle
funzioni, per evitare warning di compilazione), compilando ottengo:
    gcc -Wall -Wextra -lpthread -o prova  prova.c
    prova.c: In function ‘main’:
    prova.c:103: warning: pointer targets in passing argument 3 of
‘accept’ differ in signedness
    prova.c: At top level:
    prova.c:127: warning: unused parameter ‘param’
    /tmp/ccYG9pwt.o: In function `main':
    prova.c:(.text+0x2f8): undefined reference to `receiveThread'
    collect2: ld returned 1 exit status
Quindi molto probabilmente il compilatore prende quel pezzo, vede che
è corretto, ma poi non lo inserisce nella propria tabella dei simboli
e così alla fine lo ignora.

Ma se invece del semaforo gestisco le scritture e le letture tramite
thread non è meglio? Qualcuno può postare una sua soluzione? Please

 thread non è meglio? Qualcuno può postare una sua soluzione? Please
Puoi spiegare meglio cosa intendi dire con la tua prima domanda?
In generale però se hai una risorsa condivisa che deve essere acceduta
in modo sequenziale da tanti thread, piuttosto che usare i semafori,
ti consiglio di usare i mutex (pthread mutex) che sono più semplici da
usare... e a mio parere funzionano anche meglio.
Per quanto riguarda il postare un soluzione.. considera che ci
vorrebbe qualche dettaglio in più su quali sono le specifiche di
questa applicazioncina... ma in generale non puoi pretendere che altri
facciano il programma al posto tuo... primo perché ci vuole un po' di
tempo.
Comunque, in linea generica, ti consiglio di tenere una copia
dell'elenco telefonico in memoria (per la consultazione) e di scrivere
su disco solo quando si inseriscono nuovi elementi. Mi pare di capire
che la modifica di elementi esistenti non è prevista.