#c #multithreading #cygwin #named-pipes
#c #многопоточность #cygwin #именованные каналы
Вопрос:
Заблокированное открытие именованного канала в Cygwin приводит к зависанию другого потока при попытке открыть любой файл, включая простой текстовый файл. Приведенный ниже код воспроизводит проблему в cygwin 3.1.6(0.340/5/3 ) и отлично работает (не зависает) на RHEL 7.
#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <thread>
#include <sys/stat.h>
#include <fcntl.h>
void openFile() {
int fd;
printf("inside new threadn");
sleep(10); // Ensure main thread reaches call to open()
printf("opening a simple filen");
if((fd = open("simpleFile", 0600)) == -1) { // simpleFile is a simple text file in the filesystem
printf("failed opening a simple filen");
}
printf("simple file opened successfullyn");
close(fd);
printf("simple file closedn");
}
int main(int argc, char *argv[]) {
int fd;
char readBuffer[PIPE_BUF];
printf("creating named pipen");
if (mkfifo("namedPipe", 0600)) {
printf("creating named pipe failedn");
}
printf("creating threadn");
std::thread pipeCreator = std::thread(openFile);
printf("opening named pipe for readn");
fd = open("namedPipe", O_RDONLY); // Block will only release when we echo something into namedPipe
printf("reading from named pipen");
if (read(fd, readBuffer, PIPE_BUF) == -1) {
printf("error reading from pipen");
}
printf("read successfully from named pipen");
pipeCreator.join();
return 0;
}
Запуск этого печатает:
creating named pipe
creating thread
opening named pipe for read
inside new thread
opening a simple file
И затем блокируется до тех пор, пока не будет открыта другая сторона именованного файла.
После освобождения он записывает остальные отпечатки:
reading from named pipe
simple file opened successfully
read successfully from named pipe
simple file closed
В RHEL это выводит ожидаемый результат:
creating named pipe
creating thread
opening named pipe for read
inside new thread
opening a simple file
simple file opened successfully
simple file closed
И только тогда основной поток зависает до тех пор, пока что-то не будет передано в NamedPipe.
Мы работаем над обходным решением, которое не будет блокировать, но это связано с напряженным ожиданием, что не очень хорошо. Кто-нибудь может объяснить это поведение?
Комментарии:
1. Я могу только подтвердить ваши выводы. Я пробовал с g 9.3.0 и clang 8.0.1 в cygwin, и для меня это действует одинаково. Я попытался посмотреть,
strace -f
дал ли какие-либо подсказки, но я не видел ничего другого, кроме того, что он просто зависал наopen()
. :-/
Ответ №1:
В Cygwin open
системный вызов блокирует таблицу файловых дескрипторов на все время системного вызова. Что означает, что все open
системные вызовы по существу упорядочены.
См syscalls.cc/open()
:
extern "C" int
open (const char *unix_path, int flags, ...)
{
. . .
cygheap_fdnew fd; // <-- here
И cygheap.h
:
class cygheap_fdnew : public cygheap_fdmanip
{
public:
cygheap_fdnew (int seed_fd = -1, bool lockit = true)
{
if (lockit)
cygheap->fdtab.lock (); // <-- here
. . .
Я не вижу простого способа обойти это, но я предполагаю, что должна быть возможность разблокировать таблицу fd после создания дескриптора, по крайней мере, в случае fifo (см. fhandler_fifo
), поскольку fifo блокируется open
. Вы можете обсудить это подробнее на cygwin-developers.
Комментарии:
1. Наш текущий обходной путь заключается в открытии с флагом O_NONBLOCK и отключении, пока результат чтения равен 0 прочитанным байтам