g++和gcc在pthread_cleanup_push/pop上的行为不同

svmlkihl  于 2023-01-13  发布在  其他
关注(0)|答案(1)|浏览(144)

这是我的密码

#include <pthread.h>
#include <stdio.h>

void cleanup(void *arg) {
    printf("cleanup: %s\n", (const char*)arg);
}

void *thr_fn1(void *arg) {
    printf("thread 1 strat\n");
    pthread_cleanup_push(cleanup, (void*)"thread 1 first handler");
    pthread_cleanup_push(cleanup, (void*)"thread 1 first handler");

    if(arg)
        return (void*)1;

    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);

    return (void*)1;
}

void *thr_fn2(void *arg) {
    printf("thread 2 strat\n");
    pthread_cleanup_push(cleanup, (void*)"thread 2 first handler");
    pthread_cleanup_push(cleanup, (void*)"thread 2 first handler");

    if(arg)
        return (void*)2;

    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);

    return (void*)2;
}

int main() {
    int err;
    pthread_t tid1, tid2;
    void *tret;

    pthread_create(&tid1, NULL, thr_fn1, (void*)1);
    pthread_create(&tid2, NULL, thr_fn2, (void*)1);

    pthread_join(tid1, &tret);
    printf("pthread 1 exit code %ld\n", tret);
    pthread_join(tid2, &tret);
    printf("pthread 2 exit code %ld\n", tret);

    return 0;
}

现在我使用gccg++运行它

$ gcc main.c -o main
$ ./main
thread 2 strat
thread 1 strat
pthread 1 exit code 1
pthread 2 exit code 2
$ g++ main.c -o main
$ ./main
thread 1 strat
cleanup: thread 1 first handler
cleanup: thread 1 first handler
thread 2 strat
cleanup: thread 2 first handler
cleanup: thread 2 first handler
pthread 1 exit code 1
pthread 2 exit code 2
$

1.为什么他们的行为不同?
1.其他函数的行为是否与此类似?
1.我发现gccg++的实现是不同的。那么哪一个是更好的实现呢?

xmjla07d

xmjla07d1#

在Linux上,pthread_cleanup_push()pthread_cleanup_pop()函数被实现为宏,它们分别扩展为包含{}的文本。

#  define pthread_cleanup_push(routine, arg) \
  do {                                       \
    __pthread_cleanup_class __clframe (routine, arg)

如果使用g编译,__pthread_cleanup_class是一个C类:

#ifdef __cplusplus
/* Class to handle cancellation handler invocation.  */
class __pthread_cleanup_class
{
  void (*__cancel_routine) (void *);
  void *__cancel_arg;
  int __do_it;
  int __cancel_type;

 public:
  __pthread_cleanup_class (void (*__fct) (void *), void *__arg)
    : __cancel_routine (__fct), __cancel_arg (__arg), __do_it (1) { }
  ~__pthread_cleanup_class () { if (__do_it) __cancel_routine (__cancel_arg); }
  void __setdoit (int __newval) { __do_it = __newval; }
  void __defer () { pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED,
                                           &__cancel_type); }
  void __restore () const { pthread_setcanceltype (__cancel_type, 0); }
};

它的行为和任何类一样,它的析构函数在作用域末尾运行.
在C语言中,使用gcc时,清理处理程序需要pthread_exit(),但您的代码需要return
1.当一个线程通过调用pthread_exit(3)终止时,所有清理处理程序都将按照上一点所述执行。(如果线程通过执行线程启动函数的返回而终止,则不会调用清理处理程序。)

相关问题