【问题标题】:Threads are created, then all exit before critical region创建线程,然后在临界区之前全部退出
【发布时间】:2016-11-05 22:40:28
【问题描述】:

我需要为创建 8 个线程的类编写一个程序。 4个生产者,4个消费者。生产者需要循环,并随机发送 SIGUSR1 或 SIGUSR2 到所有消费者线程。如果他们收到了 SIGUSR1,则只有 2 个应该注册,另外 2 个注册 SIGUSR2。

当我尝试运行它时,所有线程都已创建,所有 4 个生产者线程都打印了“prod ready”,两个线程都打印了“waiting 1”,但是“waiting 2”打印了 3 次,然后所有线程都退出了。在调试结束时,它说进程正常退出。

我需要使用信号量来控制关键区域。任何帮助都会很棒。

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

#define NP  4
#define NC1 2
#define NC2 2
#define CNT 10

void handler1(int signum);
void handler2(int signum);

typedef struct {
    int sent;
    int received;
    int buf[1];   
    int SIG1;              
    int SIG2;              
    sem_t con;         
    sem_t prod;          
} sbuf_t;

sbuf_t buff;

void *producer() {
    printf("prod ready \n");
    int s;
    while(1){
        sem_wait(&buff.prod);
        s=rand()%2;
        if(s==1){
            buff.sent++;
            kill(0,SIGUSR1);
        }
        else if(s==2){
            buff.sent++;
            kill(0,SIGUSR2);

        }sem_post(&buff.prod);
    }

}

void *consumer1() {
    signal(SIGUSR1, handler1);
    printf("waiting 1\n");
    while(1){

    }
}

void *consumer2() {
    signal(SIGUSR2, handler2);
    printf("waiting 2\n");
    while(1){

    }
}

void handler1(int signum){
    if(signum==SIGUSR1){
        sem_wait(&buff.con);
        printf("Caught 1\n");
        buff.received++;
        buff.SIG1++;

        sem_post(&buff.con);
    }
}

void handler2(int signum){
    if(signum==SIGUSR2){
        sem_wait(&buff.con);
        printf("caught 2 \n");
        buff.received++;
        buff.SIG2++;

        sem_post(&buff.con);
    }
}

void main(){
    pthread_t threads[9];
    buff.SIG1=0;
    buff.SIG2=0;
    buff.sent=0;
    buff.received=0;
    int index;


        sem_init(&buff.con, 0, 0);
    sem_init(&buff.prod, 0, 0);
    for (index = 0; index < NP; index++) {
            pthread_create(&threads[index], NULL, producer,NULL);
        }
        for (index = 0;index < NC1;index++) {
            pthread_create(&threads[index+4], NULL, consumer1,NULL);
        }
    for (index = 0;index < NC2;index++) {
            pthread_create(&threads[index+6], NULL, consumer2,NULL);
        }
}

【问题讨论】:

  • 为了便于阅读和理解:1) 一致地缩进代码。在每个左大括号“{”后缩进。在每个右大括号 '}' 之前不缩进。建议为每个缩进级别使用 4 个空格,因为即使使用可变宽度字体也是如此。切勿使用制表符进行缩进,因为每个文字处理器/编辑器的制表位/制表宽度设置不同。 2) 通过空行分隔代码块(for、if、else、while、do...while、switch、case、default)。
  • 不管 Visual Studio 会让你摆脱什么; main() 函数只有两个有效签名:int main( void )int main( int argc, char *argv[] ) I.E。它们的返回类型均为int
  • 当代码在一个字面量和其他任何东西之间进行比较是否相等时,总是把字面量放在左边,所以任何按键错误,比如使用=而不是==都会被编译器,而不是您花费数小时和数小时,因为一个简单的按键错误而变得白发。
  • 有一长串函数不能在信号处理程序中使用。其中一个被禁止的函数是printf(),因为它“可能”导致嵌套的信号事件,这将使程序崩溃。函数sem_wait() 也存在类似的考虑建议阅读可以调用函数的手册页信号(7)
  • 在 linux、system V 和 BSD 中,强烈建议不要使用函数:signal(),因为它的不可靠性和不一致的实现。强烈建议使用:sigaction()

标签: c multithreading signals signal-processing semaphore


【解决方案1】:

main()函数中,正在创建线程,

然后main() 退出。

当 main() 退出时,所有线程也都退出。

建议阅读以下函数:pthread_exit()pthread_join()

注意:以下在信号的处理和信号量的处理上有错误,但会演示pthread_join()和pthread_exit()的使用

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

#define NP  4
#define NC1 2
#define NC2 2
#define CNT 10

#define MAX_THREADS (9)

void handler1(int signum);
void handler2(int signum);

struct sbuf_t 
{
    int sent;
    int received;
    int buf[1];   
    int SIG1;              
    int SIG2;              
    sem_t con1;
    sem_t con2;         
    sem_t prod;          
};

typedef struct sbuf_t myData;
myData buff;

void *producer( void *dummy ) 
{
    (void)dummy;

    printf("prod ready \n");
    int s;

    while(1)
    {
        sem_wait(&buff.prod);
        s=rand()%2;

        if( !s )
        {
            buff.sent++;
            kill( 0, SIGUSR1 );
        }

        else // if( s )
        {
            buff.sent++;
            kill( 0, SIGUSR2 );
        }

        //sem_post(&buff.prod);
    }

    pthread_exit( NULL );
} // end thread: producer


void *consumer1( void *dummy ) 
{
    (void)dummy;

    //signal(SIGUSR1, handler1);
    printf("waiting 1\n");

    while(1)
    {
        sem_wait( &buff.con1 );
        // do something
        //sem_post( &buff.prod );
    }

    pthread_exit( NULL );
} // end thread: consumer1


void *consumer2( void *dummy ) 
{
    (void)dummy;

    //signal(SIGUSR2, handler2);
    printf("waiting 2\n");

    while(1)
    {
        sem_wait( &buff.con2 );
        // do something
        //sem_post( &buff.prod );
    }

    pthread_exit( NULL );
} // end thread: consumer2


void handler(int signum)
{
    sem_post(&buff.prod);
    if(signum==SIGUSR1)
    {
        //sem_wait(&buff.con);
        puts("Caught 1");
        buff.received++;
        buff.SIG1++;

        sem_post(&buff.con1);
    }

    else if(signum==SIGUSR2)
    {
        //sem_wait(&buff.con);
        puts("caught 2");
        buff.received++;
        buff.SIG2++;

        sem_post(&buff.con2);
    }
} // end signal handler: handler2


int main( void )
{
    pthread_t threads[ MAX_THREADS ];
    buff.SIG1=0;
    buff.SIG2=0;
    buff.sent=0;
    buff.received=0;
    int index;


    sem_init(&buff.con1, 0, 0);
    sem_init(&buff.con2, 0, 0);
    sem_init(&buff.prod, 0, 0);

    signal(SIGUSR2, handler);
    signal(SIGUSR1, handler);

    for (index = 0; index < NP; index++) 
    {
        pthread_create(&threads[index], NULL, producer,NULL);
    }

    for (index = 0;index < NC1;index++) 
    {
        pthread_create(&threads[index+4], NULL, consumer1,NULL);
    }

    for (index = 0;index < NC2;index++) 
    {
        pthread_create(&threads[index+6], NULL, consumer2,NULL);
    }

    for( size_t x=0; x<MAX_THREADS; x++ )
    {
        pthread_join( threads[x], NULL );
    }
} // end function: main

但是,处理线程信号的方法不使用kill(),因为那是用于进程的。

代码应该使用类似于:: 的函数

int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
int pthread_cond_signal(pthread_cond_t *cond)

发出信号的线程应阻塞pthread_cond_wait() 调用,直到另一个线程使用pthread_cond_signal() 发送具有相同条件变量的信号。

考虑到将信号传递给进程的类比,这有点不同,因为信号线程已经暂停其执行以等待信号,这与简单地被中断并继续运行的进程不同。

【讨论】:

  • 我尝试在 main 的末尾添加一个 wait(),并将循环定义为 while(1){},但是线程在一个信号后停止,GDB 给了我这在最后程序收到信号 SIGUSR1,用户定义的信号 1。 [切换到线程 0x7ffff77f6700 (LWP 5666)] consumer1 () at lab3.c:62 62 } (gdb) 继续。捕获 1 捕获 1 捕获 1 捕获 1 [新线程 0x7ffff4ff1700 (LWP 5671)] [新线程 0x7ffff47f0700 (LWP 5672)] [新线程 0x7ffff3fef700 (LWP 5673)]
  • wait() 函数用于单独/子进程退出时,通常是通过调用 fork() 创建子进程的地方 我已经编辑了我的答案,并提供了一些关于使用 @987654330 的建议@ 和 pthread_exit() 并继续使用 pthread_cond_wait()pthread_cond_signal()
  • 我插入了使用 phread_join()pthread_exit() 的代码的编辑,该编辑发生了什么?
【解决方案2】:

例如,您是在消费者之前创建生产者。同样在您的生产者中,您正在使用随机数生成器来确定您是发布 USR1 还是 USR2。您的描述给人的印象是您想要每个两个(而不是一些随机混合总共 4 个),这就是我看到的代码为您所做的。

【讨论】:

  • 我想要 2 个线程分别响应 USR1 和 USR2,但生产者发出哪个线程是随机的。总共4个混合是什么意思?它不应该让生产者轮流通过循环,因为信号量,并运行直到它从终端终止,因为这就是我想要它做的事情?抱歉,如果我描述性不够好,但我对线程和信号不熟悉。此外,当我使用 GDB 运行它时,它会以代码 0377 退出。
  • 这并不能回答为什么一切都(几乎)立即退出,这就是问题所在。所以这是一个糟糕的答案。
猜你喜欢
  • 1970-01-01
  • 2018-10-17
  • 1970-01-01
  • 2012-10-28
  • 1970-01-01
  • 2011-04-07
  • 1970-01-01
  • 2021-04-16
  • 2013-05-30
相关资源
最近更新 更多