C 在多线程应用程序中,如何重定向stderr&;是否根据线程将标准输出放在单独的文件中?

C 在多线程应用程序中,如何重定向stderr&;是否根据线程将标准输出放在单独的文件中?,c,linux,pthreads,C,Linux,Pthreads,我有一个多线程应用程序,我正在其中创建一个线程,如下所示: int main(int argc,char *argv[]) { pthread_t thread_id[argc-1]; int i; struct parameter thread_data[argc-1]; int status; for(i=0;i<argc-1;i++) { thread_data[i].ip_filename = argv[i+1];

我有一个多线程应用程序,我正在其中创建一个线程,如下所示:

int main(int argc,char *argv[])
{
    pthread_t thread_id[argc-1];
    int i;
    struct parameter thread_data[argc-1];
    int status;
    for(i=0;i<argc-1;i++)
    {
      thread_data[i].ip_filename = argv[i+1];
      strcpy (thread_data[i].op_filename,argv[i+1]);
      strcat (thread_data[i].op_filename,".h264");
    }

    for(i=0;i<argc-1;i++)
    {
      pthread_create (&thread_id[i], NULL , &thread_function, &thread_data[i]);
    }      
}
intmain(intargc,char*argv[])
{
pthread_t thread_id[argc-1];
int i;
结构参数线程_数据[argc-1];
智力状态;

对于(i=0;i我认为这不可能直接实现。stdin/stdout是全局变量,在线程之间共享,文件描述符也是如此


您必须创建自己的文件,并将
printf
更改为
fprintf

stdout
stderr
根据定义是唯一的流。想象一下,如果有多个
stdout
s,shell将如何重定向您的流?您需要创建自己的输出流/文件变量和u用它们来代替。这有问题吗

您可能会发现使用它很有用


你不能让一个进程在另一个终端上输出一些东西。这个进程不知道终端的情况,它只输出流,终端接收并显示流


但是,您可以做的是将其中一个流的输出定向到一个文件中,并在另一个终端中运行
tail-f

如果您真的必须这样做

首先,您需要创建两个
pthread\u key\u t
s,一个用于
stdout
,另一个用于
stderr
。可以使用
pthread\u key\u create
创建它们,并且它们必须可以从所有线程访问。让我们称它们为
stdout\u key
stderr\u key

创建线程时:

FILE *err = ..., *out = ...;
pthread_setspecific(stdout_key, out);
pthread_setspecific(stderr_key, err);
然后在头文件中:

#define stdout (FILE*)pthread_getspecific(stdout_key)
#define stderr (FILE*)pthread_getspecific(stderr_key)
#define printf(...) fprintf(stdout, ##__VA_ARGS__)
然后使用:

fprintf(stderr, "hello\n");
fprintf(stdout, "hello\n");
printf("hello\n");

但是我不推荐这种方法。

您必须跟踪每个线程使用的
文件*
/
fd
以及使用
fprintf
等。没有其他方法

对于多个终端,您需要打开程序中的每个终端。无法自动确定要打开哪个终端。请在要打开的终端外壳中运行
/bin/tty
,然后在程序中打开该终端

另一种方法是使用
AF\u UNIX
套接字侦听连接。然后编写一个单独的程序连接到该套接字。您可以在希望显示输出的终端上运行该程序。

我在线程内使用
fork()
重定向forked进程的stdout,而“true”线程位于
waitpid()
中。 问题是如何将文件传递到要重定向stdout的位置。 我使用一个全局线程池,线程将通过
pthread_equal(pthread_self(),iterator)
找到自己,然后在全局线程池结构中有一个outfile,程序应该在其中重定向stdout。 在我的例子中,我创建了一个
tmpnam()
,并将其写入线程结构,但您可以按照自己的意愿使用它

下面是一些示例代码:(动态编写)

pthread_t*t_cur=NULL;
int i、pid、newout;
char*outfile=NULL;
对于(i=0;i读取))
打破
如果(i==最大线程数)
{
printf(“无法进入全局线程池。\n”);
pthread_退出(&i);
}
if(globals.tpool[i]>outfile==NULL)//仅当未设置outfile时才重定向标准输出(这对于我来说是特别的)
{
outfile=globals.tpool[i]>outfile=malloc(L_tmpnam*sizeof(char));
tmpnam(输出文件);
}
如果((pid=fork())==0)
{
如果(输出文件!=NULL)
{
newout=open(outfile,O|u create | O|u APPEND,S|u IRUSR | S|u IRGRP | S|IWGRP);
dup2(新出,标准文件号);
关闭(新出);
}
/*你的代码在这里*/
}
其他的
waitpid(pid,NULL);
pthread_退出(&i);

我真的是在运行中编写的,我没有测试过这段代码,所以请注意修复任何错误。我没有发布真正的代码,因为调用了我自己的库。在这里,我没有检查
tmpnam()
fork()
open()
malloc()的返回值
,这是您应该做的。

pthread\u getspecific
不接受字符串参数;它接受由
pthread\u key\u create
创建的
pthread\u key\t
。如果您的代码正常工作,这纯粹是偶然的-这些字符串中的每个字符串的地址可能是唯一的,以最大键数为模。但是如果如果在低位不唯一,就会发生冲突。在任何情况下,这都是未定义的行为,如果原型存在,这也是完全非法的C(因为参数类型将是错误的)@R答案底部清楚地说明了函数不带take字符串的事实。@R我想也是你否决了我的答案,也许你应该在否决和抱怨之前学会阅读。这很公平,但为什么不干脆
s/“stdin呢“/STNIDYKEY/<代码>等。如果你做了一个编辑,我会删除下注,但是它被锁定直到有一个编辑。这是我的政策,不是我的决定;即使有大量的ReP我也不能推翻它(我可以编辑你自己的答案,但我一般认为不合适……).我认为引入这些键会增加太多的复杂性,让他无法决定是否要沿着这条路走下去,我的回答只是为了证明这是可能的。真正的问题不在于如何做到这一点,而可能在于他的程序设计,因为他首先需要这一点。
fork()
是一个单独的进程,但是…它也可能返回-1,您可能不应该将其传递给
waitpid()
pthread_t *t_cur=NULL;
int i,pid,newout;
char *outfile=NULL;

for(i=0;i<MAX_THREADS;i++)
  if(pthread_equal(pthread_self(),globals.tpool[i]->thread))
    break;
if(i==MAX_THREADS)
{
   printf("cannot find myself into global threads pool.\n");
   pthread_exit(&i);
 }
if(globals.tpool[i]->outfile == NULL) //  redirect stdout only if outfile is not set ( this is specfic for my purposes )
{
  outfile = globals.tpool[i]->outfile = malloc(L_tmpnam*sizeof(char));
  tmpnam(outfile);
}

if((pid = fork()) == 0)
{
   if(outfile!=NULL)
   {
     newout = open(outfile,O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
     dup2(newout,STDOUT_FILENO);
     close(newout);
   }
   /* your code here */
}
else
  waitpid(pid,NULL);
pthread_exit(&i);