C 断开的螺纹已赢得';尽管它运行pthread_exit,但仍不能退出?

C 断开的螺纹已赢得';尽管它运行pthread_exit,但仍不能退出?,c,multithreading,pthreads,semaphore,pthread-exit,C,Multithreading,Pthreads,Semaphore,Pthread Exit,我已经在线程池中处理一个问题好几天了。我尝试了各种不同的方法,但似乎无法解决问题。我制作了一个简单的版本,重现了这个问题 代码: #include <unistd.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <time.h> struct bsem_t bsem; pthread_

我已经在线程池中处理一个问题好几天了。我尝试了各种不同的方法,但似乎无法解决问题。我制作了一个简单的版本,重现了这个问题

代码:

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h> 


struct bsem_t bsem;
pthread_t threads[2];


/* Binary semaphore */
typedef struct bsem_t {
    pthread_mutex_t mutex;
    pthread_cond_t   cond;
    int v;
} bsem_t;

void bsem_post(bsem_t *bsem) {
    pthread_mutex_lock(&bsem->mutex);
    bsem->v = 1;
    pthread_cond_broadcast(&bsem->cond);
    pthread_mutex_unlock(&bsem->mutex);
}

void bsem_wait(bsem_t *bsem) {
    pthread_mutex_lock(&bsem->mutex);
    while (bsem->v != 1) {
        pthread_cond_wait(&bsem->cond, &bsem->mutex);
    }
    bsem->v = 0;
    pthread_mutex_unlock(&bsem->mutex);
}


/* Being called by each thread on SIGUSR1 */
void thread_exit(){
    printf("%u: pthread_exit()\n", (int)pthread_self());
    pthread_exit(NULL);
}


/* Startpoint for each thread */
void thread_do(){

    struct sigaction act;
    act.sa_handler = thread_exit;
    sigaction(SIGUSR1, &act, NULL);

    while(1){
        bsem_wait(&bsem); // Each thread is blocked here
        puts("Passed semaphore");
    }

}


/* Main */
int main(){

    bsem.v = 0;

    pthread_create(&threads[0], NULL, (void *)thread_do, NULL);
    pthread_create(&threads[1], NULL, (void *)thread_do, NULL);
    pthread_detach(threads[0]);
    pthread_detach(threads[1]);
    puts("Created threads");

    sleep(2);

    pthread_kill(threads[0], SIGUSR1);
    pthread_kill(threads[1], SIGUSR1);

    puts("Killed threads");

    sleep(10);

    return 0;
}
Created threads
Killed threads
2695145216: pthread_exit()
2686752512: pthread_exit()
问题

尽管输出似乎正确,但使用
pstree
显示两个线程中只有一个线程死亡。另一个线程保持活动状态,直到整个程序退出。为什么会这样


更新

用普通信号量替换我的自定义二进制信号量似乎可以解决这个问题,没有明显的原因

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h> 
#include <semaphore.h> 

sem_t sem;
pthread_t threads[2];


/* Caller thread will exit */
void thread_exit(){
    printf("%u: pthread_exit()\n", (int)pthread_self());
    pthread_exit(NULL);
}


/* Startpoint for each thread */
void* thread_do(){

    struct sigaction act;
    act.sa_handler = thread_exit;
    sigaction(SIGUSR1, &act, NULL);

    while(1){
        sem_wait(&sem); // Each thread is blocked here
        puts("Passed semaphore");
    }

}


/* Main */
int main(){

    sem_init(&sem, 0, 0); // Normal semaphore

    pthread_create(&threads[0], NULL, thread_do, NULL);
    pthread_create(&threads[1], NULL, thread_do, NULL);
    pthread_detach(threads[0]);
    pthread_detach(threads[1]);
    puts("Created threads in pool");

    sleep(2);

    //PROBLEM
    pthread_kill(threads[0], SIGUSR1);
    pthread_kill(threads[1], SIGUSR1);

    puts("Destroyed pool");

    sleep(10);

    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
扫描电镜;
pthread_t线程[2];
/*调用线程将退出*/
无效线程_退出(){
printf(“%u:pthread_exit()\n”,(int)pthread_self());
pthread_exit(NULL);
}
/*每个线程的起始点*/
void*thread_do(){
结构动作法;
act.sa_handler=线程_退出;
sigaction(SIGUSR1,&act,NULL);
而(1){
sem_wait(&sem);//这里每个线程都被阻塞
puts(“传递的信号量”);
}
}
/*主要*/
int main(){
sem_init(&sem,0,0);//正常信号量
pthread_create(&threads[0],NULL,thread_do,NULL);
pthread_create(&threads[1],NULL,thread_do,NULL);
pthread_detach(线程[0]);
pthread_detach(线程[1]);
放置(“池中创建的线程”);
睡眠(2);
//问题
pthread_kill(线程[0],SIGUSR1);
pthread_kill(线程[1],SIGUSR1);
看跌期权(“被摧毁的池”);
睡眠(10);
返回0;
}
从这里到不了那里 pthread_exit()未列在信号(7)手册页的“信号安全功能”中。
重写代码,使pthread_exit调用位于信号处理程序之外。

因此问题似乎是死锁

问题在于,每个线程都在二进制信号量的
bsem\u wait
内的不同位置等待:

void bsem_wait(bsem_t *bsem) {
    pthread_mutex_lock(&bsem->mutex); // THREAD 2 BLOCKED HERE
    while (bsem->v != 1) {
        pthread_cond_wait(&bsem->cond, &bsem->mutex); // THREAD 1 WAITING HERE
    }
    bsem->v = 0;
    pthread_mutex_unlock(&bsem->mutex);
}
在本例中,线程1是最快的线程。线程2是较慢的线程。当我运行终止线程的信号时,等待的线程会按预期解除阻塞并退出。问题是它从不解锁互斥锁。因此被阻塞的线程(2)将永远被阻塞。由于某些原因,线程不会被终止,因为它正在等待互斥锁

只需在退出前添加一个取消阻止,即可解决此问题:

void thread_exit(){
    printf("%u: pthread_exit()\n", (int)pthread_self());
    pthread_mutex_unlock(&mutex); //  NEW CODE
    pthread_exit(NULL);
}

这当然是一个黑客来证明正在发生什么,不应该使用。我将遵循Jasen的建议,一起摆脱信号处理器,并以其他方式解决它。也就是说,我必须确保线程贯穿整个
bsem\u wait

不要使用石膏,真的。正确使用接口。线程函数必须是
void*(*)(void*)
,而不是别的。您的程序具有未定义的行为。还要记住,在C中,空参数列表不是一个不接收参数的函数,而是一个非特定数量的参数。除非您知道自己在做什么,否则不要使用该功能。您可能还希望从中获得有关
pthread_exit
的使用和信号处理的建议。Jens Gustedt感谢您的评论,但我不知道他们与该问题有什么关系。即使按照你的建议改变事情,也不会改变问题的行为。我会调查的。然而,奇怪的是,如果我使用一个普通的信号量,事情就可以正常工作(工作代码片段附在问题上)。@Pithikos这并不奇怪,因为代码有许多不安全的操作和竞争条件,所以你可能只是在一种情况下运气不佳。特别是在使用pthread_互斥体的版本中,当一个线程持有互斥体时,您正在退出一个线程,因此,当另一个线程以不安全的方式(在信号处理程序中)调用pthread_exit()时,谁知道会发生什么。由于在信号处理程序中使用printf()而导致的挂起也并非闻所未闻。(还请注意,线程结束时不会被处理,除非对其调用pthread_join(),或者将其创建为分离的线程)。