0

几天来,我一直在处理线程池中的一个问题。我尝试了所有类型的不同的东西,但我似乎无法解决这个问题。我制作了一个简单的版本来重现该问题。

代码:

#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;
}

代码的作用是创建两个线程。两个线程都在一个二进制信号量(bsem_wait)上等待。然后在他们等待时,我向SIGUSR1两者发送信号,导致pthread_exit()在每个线程上执行。在我的终端上,它显示一切都按计划进行。

输出:

Created threads
Killed threads
2695145216: pthread_exit()
2686752512: pthread_exit()

问题

尽管输出看起来是正确的,但 usingpstree表明只有两个线程中的一个死掉了。另一个线程保持活动状态,直到整个程序退出。为什么是这样?


更新

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

#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;
}
4

2 回答 2

2

你不能从这里到达那里

pthread_exit() 未列在 signal(7) 手册页的“信号安全功能”中。重写您的代码以在信号处理程序之外调用 pthread_exit 。

于 2015-01-01T20:03:14.207 回答
0

所以这个问题似乎是一个僵局!

问题是每个线程都bsem_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是较慢的线程。当我运行信号以终止线程时,等待的线程会按预期解除阻塞并退出。问题是它永远不会解锁 mutex。所以被阻塞的线程 (2) 永远被阻塞。由于某种原因,线程不会被终止,因为它正在等待互斥体。

只需在退出前添加一个解锁,即可解决问题:

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

这当然是一个黑客来演示正在发生的事情,不应该使用。我将遵循 Jasen 的建议,一起摆脱信号处理程序并以其他方式解决它。即我必须确保线程贯穿整个bsem_wait

于 2015-01-02T13:17:43.460 回答