linux 线程等待时间(linux 线程等待)-编程知识网

linux下C中怎么让才能安全关闭线程

这个问题,首先得搞清楚线程关闭或者退出有哪些方式

线程的退出方式

如果进程中的任何线程调用exit,_Exit或_exit,则整个进程终止。 类似地,当信号的默认操作是终止进程时,发送到线程的信号将终止整个进程。单个线程可以有三种方式退出其控制流程,而不会终止整个进程。

1线程可以简单地从线程处理程序中返回,返回值是线程的退出代码。

2该线程可以被同一进程中的另一个线程取消。

3该线程可以调用pthread_exi

线程退出的返回值

#include <pthread.h> void pthread_exit(void *rval_ptr);
#include <pthread.h> int pthread_join(pthread_t thread, void **rval_ptr);

pthread_join函数的rval_ptr参数是无类型指针。进程中的其他线程可通过调用pthread_join函数来使用rval_ptr指针,调用它线程将阻塞,直到指定的线程调用pthread_exit或从其线程处理程序中返回或被取消。如果只是从其线程处理程序返回,则rval_ptr将包含返回码。如果线程被取消,则rval_ptr指定的内存位置设置为PTHREAD_CANCELED。

通过调用pthread_join,自动会将加入的线程放置在分离状态,如果线程已处于分离状态,则pthread_join可能会失败,返回EINVAL。如果我们对线程的返回值不感兴趣,我们可以将rval_ptr设置为NULL。在这种情况下,调用pthread_join允许我们等待指定的线程,但不去检索线程的终止状态。

下图显示了如何从已终止的线程中获取退出代码

linux 线程等待时间(linux 线程等待)-编程知识网

运行结果:

lj@lj-PC:~$ ./ptest

thread 1 returning

thread 2 exiting

thread 1 exit code 1

thread 2 exit code 2

线程如何取消

一个线程可以通过调用pthread_cancel函数请求取消同一进程中的另一个。

#include <pthread.h>
int pthread_cancel(pthread_t tid);

在默认情况下,pthread_cancel将使tid指定的线程的行为就像它使用PTHREAD_CANCELED参数调用pthread_exit一样。 但是,线程可以选择忽略或以其他方式控制取消的方式。 请注意,pthread_cancel不会等待线程终止。

线程可以安排函数在退出时被调用,这些函数称为线程清理处理程序。 可以为一个线程建立多个清理处理程序。 处理程序记录在堆栈中,这意味着它们的执行顺序与它们注册的顺序相反。

#include <pthread.h>
void pthread_cleanup_push(void (*rtn)(void *), void *arg);
void pthread_cleanup_pop(int execute);

当线程执行以下操作之一时,pthread_cleanup_push函数会被调用

调用pthread_exit

回复取消请求

使用非零执行参数调用pthread_cleanup_pop

如果execute参数设置为零,则不会调用cleanup函数。 在任何一种情况下,pthread_cleanup_pop都会删除最后一次调用pthread_cleanup_push所建立的清理处理程序。

下图举例如何使用线程清理处理程序。

linux 线程等待时间(linux 线程等待)-编程知识网

运行结果:

lj@lj-PC:~$ ./pclean

thread 1 start

thread 1 push complete

thread 2 start

thread 1 exit code 1

thread 2 push complete

cleanup: thread 2 second handler

cleanup: thread 2 first handler

thread 2 exit code 2

从输出中,我们可以看到两个线程都正常启动并退出,但只调用了第二个线程的清理处理程序。因此,如果线程是通过其处理函数直接返回而终止,则不会调用其清理处理程序,不过此行为在具体平台实现之间会有所不同。另请注意,清理处理程序的调用顺序与安装它们的顺序相反。

如果我们在FreeBSD或Mac OS X上运行相同的程序,我们会发现该程序会导致段错误。发生这种情况是因为在这些系统上,pthread_cleanup_push实现为在堆栈上存储某些上下文的宏。当线程1在对pthread_cleanup_push的调用和对pthread_cleanup_pop的调用之间返回时,堆栈被覆盖,并且这些平台在调用清理处理程序时尝试使用此(已损坏的)上下文。在Single UNIX Specification中,在对pthread_cleanup_push和pthread_cleanup_pop的一对匹配调用之间返回会导致未定义的行为。在这两个函数之间返回的唯一可移植方法是调用pthread_exit。

线程和进程的类似操作

从上文我们可以看到线程和进程的相似之处,见如下表格:

linux 线程等待时间(linux 线程等待)-编程知识网

讲了这么多,还有好多细节没有讲到,只要详细的了解了这些细节,我相信关于你的这个问题“linux下C中怎么让才能安全关闭线程”自然就有了答案。

linux多线程 如何恢复挂起的某个线程?

linux多线程通过发送信号来恢复挂起的某个线程。

守护线程的作用?

守护线程以及其作用

通常来说,守护线程经常被用来执行一些后台任务,但是呢,你又希望在程序退出时,或者说 JVM 退出时,线程能够自动关闭,此时,守护线程是你的首选。

“只要当前JVM实例中尚存任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束是,守护线程随着JVM一同结束工作,Daemon作用是为其他线程提供便利服务,守护线程最典型的应用就是GC(垃圾回收器),他就是一个很称职的守护者。”

Linux中,shell脚本如何使用信号机制去控制线程的开启关闭?

trap是Linux的内建命令,用于捕捉信号,trap命令可以指定收到某种信号时所执行的命令。trap命令的格式如下:trap command sig1 sig2 … sigN,当接收到sinN中任意一个信号时,执行command命令,command命令完成后继续接收到信号前的操作,直到脚本结束。 利用trap命令捕捉INT信号(即与Ctrl+c绑定的中断信号)。trap还可以忽略某些信号,将command用空字符串代替即可,如trap “” TERM INT,忽略kill %n和Ctrl+c发送的信号(kill发送的是TERM信号)。Linux更强劲的杀死进程的命令:kill -9 进程号(或kill -9 %n作业号)等价与kill -KILL 进程号。

举个例子

最近小A需要生产2015年全年的KPI数据报表,现在小A已经将生产脚本写好了,生产脚本一次只能生产指定一天的KPI数据,假设跑一次生产脚本需要5分钟,那么:

如果是循环顺序执行,那么需要时间:5 * 365 = 1825 分钟,约等于 6 天

如果是一次性放到linux后台并发执行,365个后台任务,系统可承受不住哦!

既然不能一次性把365个任务放到linux后台执行,那么,能不能实现自动地每次将N个任务放到后台并发执行呢?当然是可以的啦。

#! /bin/bash

source /etc/profile;

# —————————–

tempfifo=$$.fifo # $$表示当前执行文件的PID

begin_date=$1 # 开始时间

end_date=$2 # 结束时间

if

then

if

then

echo “Error! $begin_date is greater than $end_date”

exit 1;

fi

else

echo “Error! Not enough params.”

echo “Sample: sh loop_kpi 2015-12-01 2015-12-07”

exit 2;

fi

# —————————–

trap “exec 1000>&-;exec 1000

mkfifo $tempfifo

exec 1000$tempfifo

rm -rf $tempfifo

for ((i=1; i

do

echo >&1000

done

while

do

read -u1000

{

echo $begin_date

hive -f kpi_report.sql –hivevar date=$begin_date

echo >&1000

} &

begin_date=`date -d “+1 day $begin_date” +”%Y-%m-%d”`

done

wait

echo “done!!!!!!!!!!”

第6~22行:比如:sh loop_kpi_report.sh 2015-01-01 2015-12-01:

$1表示脚本入参的第一个参数,等于2015-01-01

$2表示脚本入参的第二个参数,等于2015-12-01

$#表示脚本入参的个数,等于2

第13行用于比较传入的两个日期的大小,>是转义

第26行:表示在脚本运行过程中,如果接收到Ctrl+C中断命令,则关闭文件描述符1000的读写,并正常退出

exec 1000>&-;表示关闭文件描述符1000的写

exec 1000

trap是捕获中断命令

第27~29行:

第27行,创建一个管道文件

第28行,将文件描述符1000与FIFO进行绑定,写的绑定,则标识对文件描述符1000的所有操作等同于对管道文件$tempfifo的操作

第29行,可能会有这样的疑问:为什么不直接使用管道文件呢?事实上这并非多此一举,管道的一个重要特性,就是读写必须同时存在,缺失某一个操作,另一个操作就是滞留,而第28行的绑定文件描述符(读、写绑定)正好解决了这个问题

第31~34行:对文件描述符1000进行写入操作。通过循环写入8个空行,这个8就是我们要定义的后台并发的线程数。为什么是写空行而不是写其它字符?因为管道文件的读取,是以行为单位的

第37~42行:

第37行,read -u1000的作用就是读取管道中的一行,在这里就是读取一个空行;每次读取管道就会减少一个空行

第39~41行,注意到第42行结尾的&吗?它表示进程放到linux后台中执行

第41行,执行完后台任务之后,往文件描述符1000中写入一个空行。这是关键所在了,由于read -u1000每次操作,都会导致管道减少一个空行,当linux后台放入了8个任务之后,由于文件描述符1000没有可读取的空行,将导致read -u1000一直处于等待。