рассмотрим следующую ситуацию: один поток (позволяет называть его A) инициализирует, устанавливает состояние сокета с listen()
, а затем ждет с accept()
. Соединение поступает в гнездо A, accept()
возвращает действительный fd. Создается новый поток (B) (с использованием std::thread
), а полученный fd передается вызываемому объекту, который запускается в потоке B. Чтение (с использованием read()
) для fd завершается с ошибкой, а errno
- 9 EBADFD
. Thread A вызывает join()
на B. Когда B не создается и fd используется (все еще через тот же вызываемый объект), чтение завершается без сбоев. Зачем? Ниже приведен код, иллюстрирующий эту ситуацию.Linux Socket файловый дескриптор с потоками
BaseFun::BaseFun(char* bufferAdr, int socket):
socket_fd(socket)
buffer(bufferAdr)
{}
BaseFun::~BaseFun()
{
close(socket_fd);
}
char* BaseFun::buffer_read()
{
if(read(socket_fd, buffer, BUFF_SIZE-1) < 0) {
std::cout<<"ERROR while READ\n"<<"ERRNO: "<<errno<<"\n"<<"FD: "<<socket_fd<<"\n";
}
return buffer;
}
DisplayMsgFun::DisplayMsgFun(char* buffer, int socket) :
BaseFun(buffer, socket)
{}
void DisplayMsgFunFun::operator()()
{
std::cout<<"Message:\n\t"<<buffer_read()<<"\nEND\n";
}
Отрывок, где выше, называется:
void Server::server_run()
{
sockaddr_in client_addr;
socklen_t c_len = sizeof(client_addr);
client_fd = accept(sock_fd, (sockaddr*)&client_addr, &c_len);
DisplayMsgFun dm(server_buffers->front().data(), client_fd);
std::thread job(dm);
job.join();
}
И main()
int main()
{
Server srv(PORT);
if (srv.server_create()) {
std::cout << "Server bind!\n";
srv.server_run();
}
else {
std::cout << "Bind fail! ERRNO: "<<errno<<"\n";
return -1;
}
return 0;
}
Несвязанный с вашей проблемой, но зачем создавать поток, если следующая вещь, которую вы делаете, это просто подождать? Я предполагаю, что вы делаете что-то еще между созданием потока и вызовом 'join'? Может быть, проблема в том, что * часть (что вы нам не показываете)? –
Мне было бы интересно узнать, как вы это исправите. Я знаю достаточно C++, чтобы определить проблему (за мой ответ), но не исправлять ее. Интересно, достаточно ли написать 'std :: thread job (std :: ref (dm))'. – Alnitak
@Alnitak Я проверил быстрый тест и 'std :: ref()' решает проблему. Но я думаю, этого будет недостаточно в «крупном масштабе», или когда я попытаюсь избавиться от этого вызова 'join()'. – Ufo