我必须编写一个多线程(比如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
}
}
Run Code Online (Sandbox Code Playgroud)
谢谢.
使用答案中的输入编辑代码: 我是否正确退出线程?
#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);
}
Run Code Online (Sandbox Code Playgroud)
ale*_*cov 13
线程终止主要有两种方法.
EINTR
).两种方法都有警告.有关更多详细信息,请参阅Pthread库中的Kill Thread.
在您的情况下,似乎是一个使用取消点的好机会.我将使用一个评论的例子.为清楚起见,省略了错误检查.
#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;
}
Run Code Online (Sandbox Code Playgroud)
阻塞/解除阻塞信号的需求是,如果您将SIGINT发送到进程,任何线程都可以捕获它.您在生成线程之前这样做,以避免让它们自己执行并需要与父级同步.创建线程后,还原掩码并安装处理程序.
如果线程分配了大量资源,取消点可能会很棘手; 在这种情况下,你将不得不使用pthread_cleanup_push()
和pthread_cleanup_pop()
,这是一个烂摊子.但如果使用得当,这种方法是可行的,相当优雅.
答案很大程度上取决于用户按下时想要做什么CtrlC.
如果您的工作线程没有修改退出时需要保存的数据,则无需执行任何操作.默认操作SIGINT
是终止进程,包括构成进程的所有线程.
但是,如果您的线程确实需要执行清理,那么您还有一些工作要做.您需要考虑两个单独的问题:
首先,信号处理程序是一种痛苦.除非你非常小心,否则你必须假设从信号处理程序调用大多数库函数是不合法的.幸运的是,sem_post
指定为异步信号安全,并且可以完美地满足您的要求:
sem_init(&exit_sem, 0, 0);
SIGINT
(以及您想要处理的任何其他终止信号)安装信号处理程序.SIGTERM
sem_post(&exit_sem);
for(;;);
主线程while (sem_wait(&exit_sem)!=0)
.sem_wait
成功之后,主线程应该通知所有其他线程它们应该退出,然后等待它们全部退出.以上也可以在没有使用信号掩码的信号量的情况下完成sigwaitinfo
,但我更喜欢信号量方法,因为它不需要你学习很多复杂的信号语义.
现在,有几种方法可以处理通知工作线程是时候退出了.我看到的一些选项:
sem_getvalue(&exit_sem)
定期检查并清理并退出,如果它返回非零值.但请注意,如果线程被无限期阻塞,例如在调用read
或中,则无法执行此操作write
.pthread_cancel
,并小心地放置取消处理程序(pthread_cleanup_push
)到处.pthread_cancel
,但也可用于pthread_setcancelstate
在大多数代码中禁用取消,并且仅在您要执行阻止IO操作时重新启用它.这样,您只需要将清理处理程序放在启用取消的位置.pthread_kill
这将导致阻塞系统调用返回EINTR
错误.然后你的线程可以对此采取行动并通过一系列故障退出正常的C方式,一直返回start函数.我不建议初学者使用方法4,因为很难做到正确,但对于高级C程序员来说,它可能是最好的,因为它允许您使用现有的C语言,通过返回值而不是"例外"来报告异常条件.
另请注意,如果您没有呼叫任何其他取消点功能pthread_cancel
,您将需要定期呼叫.否则,取消请求将永远不会被采取行动.pthread_testcancel