Данные, специфичные для потока
У меня есть клиентская программа следующим образом, и мне нужно сделать ее многопоточной, т.е. один поток на соединение. Но переменная sockfd должна оставаться глобальной для одного потока. Я понимаю, что для этого мне нужно использовать pthread_key_t, pthread_key_create... и т. Д. Но я запутался, как его использовать. Буду благодарен за любую помощь.
int sockfd;
pthread_key_t key_to_sockfd;
void error(const char *msg)
{
perror(msg);
exit(0);
}
void set_connection(char *argv[])
{
int portno;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
return;
}
void send_message()
{
char buffer[256];
int i=0,n;
do{
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
i++;
}while(i<3);
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
return;
}
void disconnect()
{
close(sockfd);
return;
}
void client_thrd(char *argv[])
{
set_connection(argv);
send_message();
disconnect();
}
int main(int argc, char *argv[])
{
pthread_t thid[2];
int i;
void *status;
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
for(i=0;i<1;i++)
pthread_create(&thid[i],NULL,(void*)&client_thrd,(void*)argv);
for(i=0;i<1;i++)
pthread_join(thid[i],&status);
return 0;
}
Я выполнил программу для одного потока и работает нормально. Но так как я увеличиваю количество потоков до более чем одного из них, это не работает из-за глобального жизнеспособного sockfd. Это тестовая программа для чего-то гораздо большего.
Спасибо и С уважением
3 ответа
Он очень прост в использовании. Ты звонишь pthread_key_create(&key_to_sockfd, NULL)
в начале вашей программы, то в каждом потоке вы увидите начальное значение NULL. Используйте функцию pthread_setspecific(key_to_sockfd, <pointer to a struct which contains sockfd>)
в каждой теме.
С этого момента каждый поток будет видеть различный указатель на структуру, которая содержит ваш sockfd. Когда ваша нить закончена, вы удаляете структуру и используете pthread_setspecific(key_to_sockfd, NULL)
Когда темы закончены, вы звоните pthread_key_delete(key_to_sockfd)
удалить хранилище. Вы также можете автоматически очистить, предоставив функцию обратного вызова pthread_key_create
освободить память, когда поток закончится.
Из того, что я вижу, вам не нужна глобальная переменная для достижения того, что вы хотите сделать. Создайте структуру данных "state" и инициализируйте ее для каждого потока перед ее запуском. void*
Параметр в интерфейсе потока сделан для этого.
Если я смотрю на ваш код, вы перезаписываете каждый поток и запускаете дескриптор сокета sockfd. Таким образом, каждый поток создаст новое соединение и получит новый sockfd. С этим кодом у вас есть хорошая возможность, что один поток закрывает соединение другого потока. Если вы хотите использовать для каждого потока свой собственный дескриптор сокета, почему бы вам не использовать указатель для совместного использования одного и того же дескриптора сокета в одном потоке?
void client_thrd(char *argv[])
{
int sockfd;
set_connection(&sockfd, argv);
send_message(&sockfd);
disconnect(&sockfd);
}