POSIX pthread 编程

2023-11-24

我必须编写一个多线程(比如 2 个线程)程序,其中每个线程执行不同的任务。此外,这些线程一旦启动就必须在后台无限运行。这是我所做的。如果方法好或者您发现一些问题,有人可以给我一些反馈吗?另外,我想知道如何在使用 Ctrl+C 终止执行后以系统的方式关闭线程。

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

这是骨架:

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

Thanks.

使用答案中的输入编辑代码:我是否正确退出线程?

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

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

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

两种方法都有警告。参考杀死 Pthread 库中的线程更多细节。

就您而言,这似乎是使用取消积分的好机会。我将使用一个带注释的示例。为了清楚起见,省略了错误检查。

#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() and pthread_cleanup_pop(),这是一团糟。但如果使用得当,这种方法是可行的,而且相当优雅。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

POSIX pthread 编程 的相关文章

随机推荐

  • scipy中样条插值的系数

    我想通过 scipy 计算样条插值的系数 在 MATLAB 中 x 0 3 y 0 1 4 0 spl spline x y disp spl coefs 它会返回 ans 1 5000 5 5000 3 0000 0 1 5000 1 0
  • 在 Javascript contenteditable div 中插入文本

    有没有办法将文本 字符串 可能有也可能没有 html 标签 插入到div 它必须是一个div而不是一个textarea 首先 我需要获取光标位置 然后在该位置插入文本 和函数类似insertAdjacentText 但只能在标签之前或之后插
  • VS调试问题,谁能帮我解释一下?

    一段C 代码 var isTrue new List
  • 压缩字体以在网络中使用

    在用作网络字体之前可以对字体进行某种压缩吗 我有一个 150kB 的字体文件 能不能压缩一下 而且如果我要求两种字体 eot and ttf两者都会被浏览器下载吗 如果您使用 FontSquirrel font face 套件生成器 htt
  • WSO2 ESB DBLookup 中介查询多行

    正如 DBLookup Mediator 的文档中所述 它仅返回查询的第一行 其他结果 如果有 将被忽略 我想知道是否有 最佳方法 来运行返回多个记录然后处理它们的查询 SELECT FROM X 现在我们正在实现 axis2 服务 但是还
  • 正则表达式匹配文件夹和所有子文件夹

    我需要为备份排除过滤器编写正则表达式以排除文件夹及其所有子文件夹 我需要匹配以下内容 folder1 statistics folder1 statistics folder2 statistics folder2 statistics 我
  • XGBoost - 具有不同曝光/偏移的泊松分布

    我正在尝试使用 XGBoost 对不等长的暴露期生成的数据的索赔频率进行建模 但无法让模型正确处理暴露 我通常会通过将 log exposure 设置为偏移量来做到这一点 你能在 XGBoost 中做到这一点吗 这里发布了类似的问题 xgb
  • firebase 身份验证/无效的自定义令牌

    我正在尝试使用 firebase admin sdk 生成自定义令牌 const uid 91f0bf4c 3e3c 441c a21d 6a7fee341db5 firebaseAdmin auth createCustomToken u
  • 如何训练 libsvm 格式的图像(像素)数据以用于 Java 识别

    我想制作一个 Java 应用程序来使用 libsvm 来识别字符 但是当进入这个过程时 我不明白如何训练图像数据以与 libsvm 一起使用 最近为了学习它 我做了一个测试现有数据 我也创建了32x32基于训练图像数据 将每个像素转换为0
  • C++:如何创建一个接受连接字符串作为参数的函数?

    我可以以某种方式设计我的日志记录功能 使其接受使用 C 的以下形式的串联字符串吗 int i 1 customLoggFunction My Integer i lt lt i lt lt customLoggFunction std co
  • SSIS 中的 UPSERT

    我正在编写一个在 SQL Server 2008 上运行的 SSIS 包 如何在 SSIS 中执行 UPSERT IF KEY NOT EXISTS INSERT ELSE IF DATA CHANGED UPDATE ENDIF ENDI
  • 如何使用 JavaBeans 集合数据集填充图表数据?

    我已经创建了一个工作 jrxml 报告 其中显示了一个由集合的数据集填充的表 List 的 Java bean 现在我想使用相同的数据集来创建图表 初学者的基本条形图 每个 bean 包含 4 个我想在条形图上显示的值 月份 正常时间 旅行
  • `all: unset` 和 `all: revert' 有什么区别

    根据 MDN 在许多情况下 revert 关键字的工作方式与 unset 完全相同 这 唯一的区别是具有由浏览器设置值的属性 或由用户创建的自定义样式表 在浏览器端设置 我不明白浏览器和自定义样式表 浏览器和自定义样式表都可以替换为all
  • Docker-Compose持久数据MySQL

    如果我运行 我似乎无法让 MySQL 数据持久化 docker compose down与以下 yml version 2 services other services data container name flask data ima
  • (如何)我可以计算枚举中的项目吗?

    当我有类似的事情时 我想到了这个问题 enum Folders FA FB FC 并想为每个文件夹创建一个容器数组 ContainerClass m containers 3 m containers FA etc 使用地图会更优雅 std
  • WebDriver Selenium API:当 Element 明显存在时,出现 ElementNotFoundErrorException!

    有时 在关闭 Javascript 的情况下在 WebDriver 上运行测试时 WebDriver 在找到某个元素并尝试单击它时会因 ElementNotFound 错误而崩溃 然而 这个元素显然是存在的 读完这篇文章后 http cod
  • 制作使用项目字段作为键的查找表的惯用方法是什么?

    我有一个收藏Foo struct Foo k String v String 我想要一个HashMap哪个有钥匙 foo k和价值foo 显然 不重新设计是不可能的Foo通过介绍Rc或克隆 复制k fn t1 let foo Foo k k
  • 迁移期间 Laravel 未配置数据库

    这可能是重复的问题 但我对以前的答案没有运气 I just git clone一个 Laravel 项目 现在我尝试做php artisan migrate 它返回以下错误 InvalidArgumentException Database
  • .NET 中的引用是如何定位的?

    NET 使用什么过程在运行时定位引用的程序集 它与在编译期间定位引用的程序集的过程是否不同 我对搜索的位置及其搜索顺序以及可能影响结果的任何参数 配置设置特别感兴趣 NET 应用程序中可以进行三种类型的引用 此答案仅涵盖下面列表中的前两个
  • POSIX pthread 编程

    我必须编写一个多线程 比如 2 个线程 程序 其中每个线程执行不同的任务 此外 这些线程一旦启动就必须在后台无限运行 这是我所做的 如果方法好或者您发现一些问题 有人可以给我一些反馈吗 另外 我想知道如何在使用 Ctrl C 终止执行后以系