首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >POSIX线程编程

POSIX线程编程
EN

Stack Overflow用户
提问于 2011-07-08 08:17:57
回答 6查看 17.3K关注 0票数 11

我必须编写一个多线程程序(比如2个线程),其中每个线程执行不同的任务。此外,一旦启动,这些线程必须在后台无限地运行。这就是我所做的。如果这个方法是好的,如果你看到了一些问题,谁能给我一些反馈吗?此外,我还想知道如何在用Ctrl+C终止执行(比如)之后,以系统的方式关闭线程。

主函数创建两个线程,并让它们无限地运行,如下所示。

这是骨架:

代码语言:javascript
复制
void    *func1();
void    *func2();

int main(int argc, char *argv[])
{   

    pthread_t th1,th2;
    pthread_create(&th1, NULL, func1, NULL);
    pthread_create(&th2, NULL, func2, NULL);

    fflush (stdout);
    for(;;){
    }
    exit(0); //never reached
}

void *func1()
{
    while(1){
    //do something
    }
}

void *func2()
{
    while(1){
    //do something
    }
} 

谢谢。

编辑的代码使用来自答案的输入:是正确退出线程的吗?

代码语言:javascript
复制
#include <stdlib.h>     /*  exit() */
#include <stdio.h>      /* standard in and output*/
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <signal.h>
#include <semaphore.h>

sem_t end;

void    *func1();
void    *func2();

void ThreadTermHandler(int signo){
    if (signo == SIGINT) {
        printf("Ctrl+C detected !!! \n");
        sem_post(&end);
        }
}
void *func1()
{
    int value;
    for(;;){
        sem_getvalue(&end, &value);
        while(!value){
            printf("in thread 1 \n");
        }
    }
    return 0;
}

void *func2()
{
    int value;
    for(;;){
        sem_getvalue(&end, &value);
        while(!value){
            printf("value = %d\n", value);
        }
    }
    return 0;
}

int main(int argc, char *argv[])
{


    sem_init(&end, 0, 0);
    pthread_t th1,th2;
    int value  = -2;
    pthread_create(&th1, NULL, func1, NULL);
    pthread_create(&th2, NULL, func2, NULL);

    struct sigaction sa;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = ThreadTermHandler;
    // Establish a handler to catch CTRL+c and use it for exiting.
    if (sigaction(SIGINT, &sa, NULL) == -1) {
        perror("sigaction for Thread Termination failed");
        exit( EXIT_FAILURE );
    }

    /* Wait for SIGINT. */
    while (sem_wait(&end)!=0){}
    //{
        printf("Terminating Threads.. \n");
        sem_post(&end);
                sem_getvalue(&end, &value);
        /* SIGINT received, cancel threads. */
        pthread_cancel(th1);
        pthread_cancel(th2);
        /* Join threads. */
        pthread_join(th1, NULL);
        pthread_join(th2, NULL);
    //}
    exit(0);
}
EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2011-08-05 16:56:52

线程终止的方法主要有两种。

  • 使用取消点。当请求取消时线程将终止,并到达取消点,从而以受控方式结束执行;
  • 使用信号。让线程安装一个信号处理程序,该处理程序提供终止机制(设置标志并响应EINTR)。

这两种方法都有警告。有关详细信息,请参阅消灭线程库中的线程

在您的情况下,这似乎是一个使用取消点的好机会。我将使用一个注释的例子。为了清楚起见,错误检查被省略了.

代码语言:javascript
复制
#define _POSIX_C_SOURCE 200809L
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void sigint(int signo) {
    (void)signo;
}

void *thread(void *argument) {
    (void)argument;
    for (;;) {
        // Do something useful.
        printf("Thread %u running.\n", *(unsigned int*)argument);

        // sleep() is a cancellation point in this example.
        sleep(1);
    }
    return NULL;
}

int main(void) {
    // Block the SIGINT signal. The threads will inherit the signal mask.
    // This will avoid them catching SIGINT instead of this thread.
    sigset_t sigset, oldset;
    sigemptyset(&sigset);
    sigaddset(&sigset, SIGINT);
    pthread_sigmask(SIG_BLOCK, &sigset, &oldset);

    // Spawn the two threads.
    pthread_t thread1, thread2;
    pthread_create(&thread1, NULL, thread, &(unsigned int){1});
    pthread_create(&thread2, NULL, thread, &(unsigned int){2});

    // Install the signal handler for SIGINT.
    struct sigaction s;
    s.sa_handler = sigint;
    sigemptyset(&s.sa_mask);
    s.sa_flags = 0;
    sigaction(SIGINT, &s, NULL);

    // Restore the old signal mask only for this thread.
    pthread_sigmask(SIG_SETMASK, &oldset, NULL);

    // Wait for SIGINT to arrive.
    pause();

    // Cancel both threads.
    pthread_cancel(thread1);
    pthread_cancel(thread2);

    // Join both threads.
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    // Done.
    puts("Terminated.");
    return EXIT_SUCCESS;
}

阻塞/解除阻塞信号的需要是,如果您向进程发送SIGINT,任何线程都可能捕获它。在生成线程之前,您可以这样做,以避免让它们自己执行并且需要与父线程同步。创建线程后,可以还原掩码并安装处理程序。

如果线程分配了大量资源,取消点可能会很棘手;在这种情况下,您将不得不使用pthread_cleanup_push()pthread_cleanup_pop(),这两种情况都很混乱。但是,如果使用得当,这种方法是可行的,而且相当优雅。

票数 14
EN

Stack Overflow用户

发布于 2011-07-08 08:26:33

这是个坏主意:

代码语言:javascript
复制
for(;;){
}

因为主线程将执行不必要的CPU指令。

如果您需要在主线程中等待,请使用pthread_join,如以下问题中所回答的:C程序中的多线程

票数 3
EN

Stack Overflow用户

发布于 2011-07-08 08:30:01

您所做的一切都很有效,我认为它没有明显的问题(只是忽略了pthread_create的返回值)。不幸的是,停止线程比您可能认为的更复杂。事实上,你想要使用信号是另一个复杂的问题。这是你能做的。

  • 在“子”线程中,使用pthread_sigmask阻止信号
  • 在主线程中,使用sigsuspend等待信号。
  • 接收到信号后,取消(pthread_cancel)子线程

您的主线程可能如下所示:

代码语言:javascript
复制
/* Wait for SIGINT. */
sigsuspend(&mask);

/* SIGINT received, cancel threads. */
pthread_cancel(th1);
pthread_cancel(th2);

/* Join threads. */
pthread_join(th1, NULL);
pthread_join(th2, NULL);

显然,您应该阅读更多关于pthread_cancel和取消点的内容。您还可以安装一个清理处理程序。当然,检查每个返回值。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6621785

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档