All threads blocked by empty pipe read
我试图自学有关C(Linux)中的多线程和多进程编程的知识。 我写了一个简短的程序,它产生一个新线程,该线程转到一个例程,该例程尝试从空FIFO进行阻塞读取,而主线程继续并打印到STDOUT。 (注意:在执行程序之前,我确实在终端中使用
我期望程序打印到屏幕"主线程",然后等待我将数据放入FIFO时阻塞。 而是,整个过程被阻塞,并且仅在将数据放入FIFO后才显示消息"主线程"。
我在这里想念什么吗? 即使生成的线程被阻塞,主线程也不应该继续运行吗? 我尝试使用fork进行测试并创建一个子进程,并得到相同的结果(两个进程都被从空FIFO读取而阻止)。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <pthread.h> #define NEWPIPE"./newfifo" typedef struct __attribute__ ((__packed__)) { int reserved :30; int threadStarted :1; int msgRcved :1; } Status; void* thread_routine(int fd, char* buffer, Status* myStatus) { int great_success = 0; myStatus->threadStarted = 1; printf("Side thread\ "); great_success = read(fd, buffer, sizeof(buffer)); if (great_success < 0) { printf("pipe failed\ "); } else { myStatus->msgRcved = 1; } } void main() { int fd; int cnt = 0; char buffer[20]; Status* myStatus; pthread_t thread_id; myStatus = (Status*) malloc(sizeof(Status)); myStatus->reserved = 0; myStatus->threadStarted = 0; myStatus->msgRcved = 0; fd = open(NEWPIPE, O_RDONLY); pthread_create(&thread_id, NULL, (void *) thread_routine(fd, buffer, myStatus), NULL); printf("Main thread\ "); while (!myStatus->threadStarted) { printf("Main thread: side thread started!\ "); } while (!myStatus->msgRcved) { sleep(1); cnt++; } printf("buffer (cnt = %d): %s\ ", cnt, buffer); } |
编辑:最新代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <pthread.h> #define NEWPIPE"./newfifo" struct Status { unsigned int reserved :30; unsigned int threadStarted :1; unsigned int msgRcved :1; }; void* thread_routine(void *arg) { int great_success = 0; int fd; char buffer[20]; struct Status* myStatus; fd = open(NEWPIPE, O_RDONLY); myStatus = arg; myStatus->threadStarted = 1; printf("Side thread\ "); while (1) { great_success = read(fd, buffer, 20); if (great_success < 0) { printf("pipe failed\ "); } else { printf("buffer : %s\ ", buffer); printf("great_success = %d\ ", great_success); great_success = 0; } } } void main() { int cnt = 0; struct Status* myStatus; pthread_t thread_id; myStatus = (struct Status*) malloc(sizeof(struct Status)); myStatus->reserved = 0; myStatus->threadStarted = 0; myStatus->msgRcved = 0; pthread_create(&thread_id, NULL, &thread_routine, (void *) myStatus); // arguments to pass to the function! printf("Main thread\ "); while (!myStatus->msgRcved) { printf("Main thread: side thread started!\ "); if (myStatus->threadStarted) { printf("spawned thread started!\ "); } sleep(1); } pthread_exit(NULL); } |
您正在将调用
1 2 3 4 | pthread_create(&thread_id, NULL, thread_routine, NULL); |
"但是争论呢?"你问?这就引出了下一点:函数
最后,推定线程启动函数需要通过返回指针值(可能是
请注意,顺便说一句,您的编译器应该吐出一些与此代码有关的警告。您应该始终解决所有编译器警告,或者确定为什么不这样做是安全的。
Instead, the entire process is blocked, and the message"Main thread" only prints after I've put data into the FIFO.
Am I missing something here?
您的主线程在此行被阻止:
1 | fd = open(NEWPIPE, O_RDONLY); |
因为FIFO的非阻塞,只读打开将阻塞,直到写入器可用为止。您的主线程最终将被解除阻塞,而不是在将数据写入FIFO时,而只是在打开FIFO进行写入时才解除阻塞。
@JohnBollinger在其答案中讨论的代码中还有其他问题。但是,FIFO语义是为什么您看不到预期的初始输出的原因。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | the following is a way to open a named pipe, so there is no need for any (before running application) processing needed. enum enumReturnStatus create_Pipe( INT32 taskSelector ) { enum enumReturnStatus returnStatus = eRS_Success; // indicate success char *pTask_NameString = NULL; char Pipe_NameString[ 100 ] = {'\\0'}; struct stat statInfo; // will contain info on a file // and is used to determine if the pipe already exists INT32 mkfifoStatus = 0; INT32 statStatus = 0; if( 0 >= Pipe_Parameters[ taskSelector ].Pipe_FD ) { // then pipe not open pTask_NameString = get_pTask_NameString( taskSelector ); if( NULL == pTask_NameString ) { // task not configured return( eRS_Failure ); } /* ********************************************************************* * implied else, task configured * ******************************************************************** */ // create pipe name string sprintf( Pipe_NameString,"/tmp/Pipe_2%s", pTask_NameString ); // check if pipe already exists statStatus = stat(Pipe_NameString, &statInfo); if( (statStatus)&&(ENOENT == errno) ) { // then, FIFO pipe does not exist // create the pipe umask(0); // maybe use mknode() instead of mkfifo() // mknod(pPipe_name, S_IFIFO | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0 ); // 0666 allows anyone to read/write the pipe mkfifoStatus = mkfifo( Pipe_NameString, 0666 ); if ( -1 == mkfifoStatus ) { CommonWriteCdsLog( eLL_Critical, get_pFormatString( eFormat_CFFL_string_string ), __FILE__, __LINE__, "LibFunc:mkfifo() failed to create pipe", strerror( errno ) ); fprintf(stderr,"mkfifo failed: %s \ ",strerror( errno )); fflush(stderr); system("sync; sync;" ); exit( EXIT_FAILURE ); } } // endif ( pipe doesn't exist ) if( !mkfifoStatus && !statStatus ) { // then pipe created or already exists if( 0 >= Pipe_Parameters[taskSelector].Pipe_FD ) { // then, pipe not yet open // note: use O_RDWR so open will not hang Pipe_Parameters[taskSelector].Pipe_FD = open( Pipe_NameString, O_CREAT|O_RDWR ); if( 0 >= Pipe_Parameters[taskSelector].Pipe_FD ) { // then open failed CommonWriteCdsLog( eLL_Critical, get_pFormatString( eFormat_CFFL_string_string ), __FILE__, __LINE__, "LibFunc:open() failed for pipe", strerror( errno ) ); } else { // else open successful ; } // endif( open for read successful ) } // endif( pipe not already open ) } // endif( pipe created or already exists ) } // endif( pipe not open ) return( returnStatus ); } // end create_Pipe() |
这段代码:
1 2 3 4 5 | typedef struct __attribute__ ((__packed__)) { int reserved :30; int threadStarted :1; int msgRcved :1; } Status; |
由于代码正在使用带符号的值,并且结构定义不应该作为typedef进行typedef定义,因此会出现问题:
- 使代码模糊不清,
- 在读者中引起混乱
- 并使编译器名称空间混乱
这是定义结构的首选方法的示例
(并使用位字段纠正问题)
1 2 3 4 5 6 | struct status { unsigned int reserved :30; unsigned int threadStarted :1; unsigned int msgRcved :1; }; |
不需要packed属性,因为所有位都适合单个unsigned int存储区。通过变量定义和函数参数列表中的