C - Таинственная ошибка сегментации с резьбой - PullRequest
1 голос
/ 02 августа 2011

это простая программа, над которой я работал, которая прослушивает сокет и запускает новый поток для обработки каждого соединения с указанным сокетом.В моем цикле while я получаю ошибку сегментации, которая имеет отношение к pthread_create (если я прокомментирую эту строку, программа правильно зацикливается).Мои знания указателей в лучшем случае посредственные, и отладка с помощью gdb не принесла ничего полезного.Это вывод gdb:

#0  0x0000000000000000 in ?? ()
#1  0x000000080064f4f1 in pthread_getprio () from /lib/libthr.so.3
#2  0x0000000000000000 in ?? ()
Error accessing memory address 0x7fffffbff000: Bad address.

Программа успешно проходит цикл while, правильно получает и отвечает на соединение в сокете, но затем, прежде чем попасть во второй цикл while, программа не запускаетсяa Ошибка Сегментации.

Вот сокращенная версия моей программы:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <pthread.h>

#define UNIX_PATH_MAX 100
#define SOCK_PATH "/tmp/demo_socket"

/*===============> CONNECTION HANDLER FUNCTION <=================*/
void *connection_handler(int connection_fd)
{
    int nbytes;
    char buffer[256];

nbytes = read(connection_fd, buffer, 256); 
buffer[nbytes] = 0;
printf("\tMESSAGE FROM CLIENT: %s\n", buffer);

nbytes = snprintf(buffer, 256, "Hello from the server!");
write(connection_fd, buffer, nbytes);

close(connection_fd);

return;
}


/*==========================> MAIN <=============================*/
int main(void)
{
    struct sockaddr_un addr; //socket address information
    int sock_fd, conn_fd; //socket file descriptors
    socklen_t addr_len = sizeof(struct sockaddr_un); //size of sockaddr_un structure
    pid_t child_pid; //pid holder
    pthread_t thread; // thread identifier 


sock_fd = socket(AF_UNIX, SOCK_STREAM, 0); 
if (sock_fd < 0)
    return 1;
unlink(SOCK_PATH);



memset(&addr, 0, addr_len); 

addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCK_PATH, sizeof(addr.sun_path) - 1); // Copies up to sizeof(addr.sun_path)-1 bytes from SOCK_PATH into addr.sun_path 
printf("> Socket sun_family = %d (AF_UNIX), Socket sun_path = %s ...\n", addr.sun_family, addr.sun_path);


/*----------------------FAIL CHECKS-------------------------*/
if (bind(sock_fd, (struct sockaddr *) &addr, addr_len) != 0) 
    return 1;
if (listen(sock_fd, 5) != 0)
    return 1;

printf("> Listening to socket bound at %s ...\n\n", SOCK_PATH);


/*--------------------WHILE LOOP----------------------------*/
while ( (conn_fd = accept(sock_fd, (struct sockaddr *) &addr, &addr_len)) > -1) {

    pthread_create(&thread , NULL, connection_handler(conn_fd), NULL); 

    printf("> Closing connection at %d inside server process ...\n", conn_fd);
    close(conn_fd);
    printf("> Reached bottom of loop!\n");
    }


/*---------------------------FIN------------------------------*/
close(sock_fd);
unlink(SOCK_PATH);
printf("> Socket closed and unlinked from path ... Done!\n ");
return 0;
}

Любая помощь будет принята с благодарностью!

Ответы [ 4 ]

3 голосов
/ 02 августа 2011

Это неправильно:

pthread_create(&thread , NULL, connection_handler(conn_fd), NULL);

pthread_create требует адрес функции для запуска в новом потоке.Ваш код вызывает connection_handler в главном потоке, а затем передает результат connection_handler в pthread_create в качестве адреса функции.

Вам нужно следующее:

pthread_create(&thread , NULL, connection_handler, (void*)conn_fd);

Вам также нужно изменить connection_handler, чтобы взять void* вместо int:

void *connection_handler(void* arg)
{
  intptr_t connection_fd = (intptr_t)arg;
  ...
}
1 голос
/ 02 августа 2011

Вы используете pthread_create неверно. третий аргумент должен быть указателем на функцию типа void *(*start_routine) (void *), вместо этого вы передаете возврат connection_handler.

Измените connection_handler, чтобы получить аргумент void * (и убедитесь, что он возвращает фактическое значение), например.

#include <stdint.h>

void *connection_handler(void *arg)
{
    intptr_t connection_fd = (intptr_t)arg;
    ...
    return NULL;
}

и измените свой вызов на что-то вроде следующего

pthread_create(&thread, NULL, &connection_handler, (void *)conn_fd);

Вы также должны убедиться, что вы начали отсоединять нить, отсоедините нить с помощью pthread_detach или присоединитесь к ней позже с pthread_join

0 голосов
/ 02 августа 2011

Скорее всего, потому что вы закрываете сокетное соединение в двух местах.Есть большая вероятность, что за один прогон потока он еще не дошел до write, но в родительском потоке уже закрыл соединение.

Зачем вам нужно создавать столько потоков?Разве одного рабочего потока не хватит?Вы можете накапливать задания в этом рабочем потоке ...

0 голосов
/ 02 августа 2011
buffer[nbytes] = 0;

Это переполнится, если вы прочитали 256 байтов.Увеличьте размер буфера или уменьшите размер чтения на единицу.

...