确保SHUTDOWN钩子上的所有事务都完成...示例代码检查

时间:2011-11-01 11:22:37

标签: c

我实际上早些时候曾在Correct way to shutdown C application to ensure CRITICAL sections completed?提出类似的问题,但我想重新开始并问以下任何人都可以看到以下代码和基本问题。

我基本上提出了一个概念证明,它是这样的:

  • 主应用程序启动需要“处理事务中的消息”的线程
  • 当用户点击CTRL-C时,我需要应用程序优雅地运行,直到当前线程事务完成为止

注意:从线程到MAIN应用程序的回调是必不可少的,我想知道这是否是“糟糕的编程习惯”....

代码正在输出,这是一个示例:

lynton@lynton ~/Desktop/ThreadTest $ ./main
Main program started
In thread testMainLoop
Transaction started in spawned thread
onBeginTransaction in main thread
onMessageArrived in main thread
onCommitTransaction in main thread
Transaction ended in spawned thread
Transaction started in spawned thread
onBeginTransaction in main thread
onMessageArrived in main thread
onCommitTransaction in main thread
Transaction ended in spawned thread
Transaction started in spawned thread
onBeginTransaction in main thread
onMessageArrived in main thread
onCommitTransaction in main thread
Transaction ended in spawned thread
^CIn shutdown hook...
Thread still running
listenForMessages loop completed in spawned thread
In onProcessingComplete in main thread
Exciting testMainLoop
All thread transactions complete
Main program exiting
lynton@lynton ~/Desktop/ThreadTest $ 

在上面你可以看到启动了关闭钩子并且应用程序正常结束......

基础测试代码如下:

请特别注意“(* onProcessingCompleteCallbackFunc)(TRUE);”从线程调用到主应用程序,向主应用程序说该线程是100%完成的。 pthread_join似乎没有用,因为我需要它到这里....

注意:以下是我创建的主应用程序使用的SHARED LIB(libwmq_sender.so)。

wmq_sender.h

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define TRUE 0
#define FALSE 1 

int wmq_sender_start();
int wmq_sender_stop();
void wmq_sender_registerOnBeginTransactionCallback(int (*callbackFunc)(char *tid));
void wmq_sender_registerOnCommitTransactionCallback(int (*callbackFunc)(char *tid));
void wmq_sender_registerOnMessageArrivedCallback(int (*callbackFunc)(char *tid, char *buffer, int size));
void wmq_sender_registerOnProcessingCompleteCallback(void (*callbackFunc)(int completeFlag));
int listenForMessages();

int (*onBeginTransactionCallbackFunc)(char *tid);
int (*onCommitTransactionCallbackFunc)(char *tid);
int (*onRollbackTransactionCallbackFunc)(char *tid);
int (*onMessageArrivedCallbackFunc)(char *tid, char *buffer, int size);
void (*onProcessingCompleteCallbackFunc)(int completeFlag);

int running;
int rc;
int transactionRunning;

wmq_sender.c

#include "wmq_sender.h"

int listenForMessages(){
    char *uuid = NULL;; 
    char *buffer = NULL;
    uuid = malloc(10 * sizeof(char));
    strcpy(uuid, "1234567891");
    buffer = malloc(11 * sizeof(char));
    strcpy(buffer, "test_buffer");

    while(running == TRUE){
        printf("Transaction started in spawned thread\n");
        transactionRunning = TRUE;
        (*onBeginTransactionCallbackFunc)(uuid);
        (*onMessageArrivedCallbackFunc)(uuid, buffer, 11);
        (*onCommitTransactionCallbackFunc)(uuid);
        transactionRunning = FALSE;
        printf("Transaction ended in spawned thread\n");
        sleep(2);
    }   
    printf("listenForMessages loop completed in spawned thread\n");
    free(uuid);
    free(buffer);
    (*onProcessingCompleteCallbackFunc)(TRUE);
    return 0;
}

int wmq_sender_start(){ 
    return listenForMessages();
}

int wmq_sender_stop(){
    running = FALSE;
    return 0;
}

void wmq_sender_registerOnBeginTransactionCallback(int (*callbackFunc)(char *tid)){
    onBeginTransactionCallbackFunc = callbackFunc;
}
void wmq_sender_registerOnCommitTransactionCallback(int (*callbackFunc)(char *tid)){
    onCommitTransactionCallbackFunc = callbackFunc;
}
void wmq_sender_registerOnMessageArrivedCallback(int (*callbackFunc)(char *tid, char *buffer, int size)){
    onMessageArrivedCallbackFunc = callbackFunc;
}
void wmq_sender_registerOnProcessingCompleteCallback(void (*callbackFunc)(int completeFlag)){
    onProcessingCompleteCallbackFunc = callbackFunc;
}

以下是生成线程并正常关闭等的MAIN应用程序。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <time.h>
#include "wmq_sender.h"

#define TRUE 0
#define FALSE 1

void *testMainLoop(void *arg);
void shutdownHook(int sig);
int main(int argc, char * argv[]);
int onBeginTransaction(char *tid);
int onCommitTransaction(char *tid);
int onMessageArrived(char *tid, char *buffer, int size);
void onProcessingComplete(int completeFlag);

pthread_t testThread;
int threadRunning;
int rc;

void *testMainLoop(void *arg){
    printf("In thread testMainLoop\n");
    wmq_sender_registerOnBeginTransactionCallback(onBeginTransaction);
    wmq_sender_registerOnCommitTransactionCallback(onCommitTransaction);
    wmq_sender_registerOnMessageArrivedCallback(onMessageArrived);
    wmq_sender_registerOnProcessingCompleteCallback(onProcessingComplete);
    threadRunning = TRUE;
    rc = wmq_sender_start();
    printf("Exciting testMainLoop\n");
}

void shutdownHook(int sig){
    printf("In shutdown hook...\n");
    rc = wmq_sender_stop();
    while(threadRunning == TRUE){
        printf("Thread still running\n");
        sleep(2);
    }
    printf("All thread transactions complete\n");
}

void onProcessingComplete(int completeFlag){
    printf("In onProcessingComplete in main thread\n");
    threadRunning = FALSE;
}

int main(int argc, char * argv[]){
    (void) signal(SIGINT, shutdownHook);
    printf("Main program started\n");
    rc = pthread_create(&testThread, NULL, testMainLoop, (void *)argv);
    pthread_join(testThread, NULL);
    printf("Main program exiting\n");
    return 0;
}

int onBeginTransaction(char *tid){
    printf("onBeginTransaction in main thread\n");
    return 0;
}
int onCommitTransaction(char *tid){
    printf("onCommitTransaction in main thread\n");
    return 0;
}
int onMessageArrived(char *tid, char *buffer, int size){
    printf("onMessageArrived in main thread\n");
    return 0;
}

在我的测试机器上编译是:

gcc -m64 -Wall -g -I./ -c ./main.c -o ./main.o
gcc -m64 -o ./main ./main.o -L./ -L/usr/lib -L/usr/local/lib -lpthread -lwmq_sender

gcc -m64 -Wall -g -c -I./ -I/usr/local/include/ -fPIC ./wmq_sender.c -o ./wmq_sender.o
gcc -shared -o ./libwmq_sender.so ./wmq_sender.o

export LD_LIBRARY_PATH="/home/lynton/Desktop/ThreadTest"

您是否认为我使用CALLBACKS告诉主应用程序线程完整等方式有什么问题?

非常感谢任何帮助或建议; - )

由于

林顿

1 个答案:

答案 0 :(得分:1)

你确实意识到你的回调函数实际上是在线程上运行的吗?据我所知,你的主线程只是创建另一个线程,它完成所有事情,然后等待它完成。我现在没有看到创建第二个帖子的任何意义。

无论如何,你遇到的另一个可怕问题是你的信号处理程序调用{​​{1}}和printf。我非常确定sleep在信号处理程序中调用是不安全的,printf也不是。真的应该做的就是设置一个标志来说“终止”然后返回。

根据C99标准,您无法可靠地分配任何未声明为sleep的静态变量或调用除volatile sig_atomic_tabort()或{{_Exit()之外的任何标准库函数1}}和最后一个与您收到的信号相同的信号。