Данные, специфичные для потока - PullRequest
0 голосов
/ 14 сентября 2011

У меня есть клиентская программа следующим образом, и мне нужно сделать ее многопоточной, то есть один поток на соединение. Но переменная 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 ]

3 голосов
/ 14 сентября 2011

Это очень удобно. Вы вызываете 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 для освобождения памяти после завершения потока.

2 голосов
/ 14 сентября 2011

Из того, что я вижу, вам не нужна глобальная переменная для достижения того, что вы хотите сделать.Создайте структуру данных «state» и инициализируйте ее для каждого потока перед ее запуском.Для этого создан параметр void* в интерфейсе потока.

0 голосов
/ 14 сентября 2011

Если я посмотрю ваш код, вы перезаписываете каждый поток и запускаете дескриптор сокета sockfd. Таким образом, каждый поток создаст новое соединение и получит новый sockfd. С этим кодом у вас есть хорошая возможность, что один поток закрывает соединение другого потока. Если вы хотите использовать для каждого потока свой собственный дескриптор сокета, почему бы вам не использовать указатель для совместного использования одного и того же дескриптора сокета в одном потоке?

void client_thrd(char *argv[])
{
  int sockfd;
  set_connection(&sockfd, argv);
  send_message(&sockfd);
  disconnect(&sockfd);
}
...