Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PTHREAD_CANCEL_ASYNCHRONOUS取消整个进程_C_Multithreading_Pthreads - Fatal编程技术网

PTHREAD_CANCEL_ASYNCHRONOUS取消整个进程

PTHREAD_CANCEL_ASYNCHRONOUS取消整个进程,c,multithreading,pthreads,C,Multithreading,Pthreads,在C程序中,我使用PTHREAD\u CANCEL\u ASYNCHRONOUS从父线程触发PTHREAD\u CANCEL后立即取消线程。但是,由于分割错误,导致整个过程崩溃。子线程的任务是从数据库服务器获取一些数据。我的逻辑是,如果它在10秒内没有得到数据,线程应该从父线程被杀死 我只想杀死子线程,而不是整个过程 struct str_thrd_data { SQLHANDLE hstmt; int rc; bool thrd_complete

在C程序中,我使用
PTHREAD\u CANCEL\u ASYNCHRONOUS
从父线程触发PTHREAD\u CANCEL后立即取消线程。但是,由于分割错误,导致整个过程崩溃。子线程的任务是从数据库服务器获取一些数据。我的逻辑是,如果它在10秒内没有得到数据,线程应该从父线程被杀死

我只想杀死子线程,而不是整个过程

struct str_thrd_data
{
        SQLHANDLE hstmt;
        int rc;
        bool thrd_completed_flag;
};


void * str_in_thread_call(void *in_str_arg)
{
        int thrd_rc;
        struct str_thrd_data *str_arg;
        str_arg = in_str_arg;

        thrd_rc = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
        if (thrd_rc != 0)
               handle_error_en(thrd_rc, "pthread_setcancelstate");

        thrd_rc = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        if (thrd_rc != 0)
               handle_error_en(thrd_rc, "pthread_setcancelstate");

        thrd_rc = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
        if (thrd_rc != 0)
               handle_error_en(thrd_rc, "pthread_setcanceltype");
        // Code to call SQL Dynamic Query from a Database Server. This takes time more than 10 seconds.
      thrd_rc = SQLExecute(hstmt);
        printf("\n*********************Normal Thread termination withing timelimit %d\n",str_arg->rc);
        str_arg->thrd_completed_flag = true;

}

int main()
{
        printf("\nPJH: New THread created.\n");
        pthread_attr_t tattr;
        pthread_t th;
        size_t mysize = 1;

        struct str_thrd_data atd;

        atd.hstmt = hstmt;
        atd.rc= rc;
        atd.thrd_completed_flag = false;

        thrd_rc = pthread_attr_init(&tattr);
        thrd_rc = pthread_attr_setstacksize(&tattr, mysize);
        thrd_rc = pthread_create(&th, &tattr, &str_in_thread_call, &atd);
        if (thrd_rc != 0)
               handle_error_en(thrd_rc, "pthread_create");

        // While Loop tp count till 10 seconds.
        while(timeout !=0)
        {
                printf("%d Value of rc=%d\n",timeout, atd.rc);
                if(atd.rc != 999) break;
                timeout--;
                usleep(10000);
        }
        rc = atd.rc;
        //Condition to check if thread is completed or not yet.
          if(atd.thrd_completed_flag == false)
        {
                //Thread not comepleted within time, so Kill it now.
                printf("PJH ------- 10 Seconds Over\n");
                thrd_rc = pthread_cancel(th);
                printf("PJH ------- Thread Cancelled Immediately \n");    
                if (thrd_rc != 0)
                {
                       handle_error_en(thrd_rc, "pthread_cancel");
                }
                printf("\nPJH &&&&&&&& Thread Cancelled Manually\n");
        }
        thrd_rc = pthread_join(th,NULL);
        // some other job .....
}
gdb进程\u name corefile
显示以下回溯:-大部分是所有SQL库函数

#0  0xffffe410 in __kernel_vsyscall ()
#1  0x0059fe30 in raise () from /lib/libc.so.6
#2  0x005a1741 in abort () from /lib/libc.so.6
#3  0xdef3f5d7 in ?? () from /usr/lib/libstdc++.so.5
#4  0xdef3f624 in std::terminate() () from /usr/lib/libstdc++.so.5
#5  0xdef3f44c in __gxx_personality_v0 () from /usr/lib/libstdc++.so.5
#6  0x007e1917 in ?? () from /lib/libgcc_s.so.1
#7  0x007e1c70 in _Unwind_ForcedUnwind () from /lib/libgcc_s.so.1
#8  0x007cda46 in _Unwind_ForcedUnwind () from /lib/libpthread.so.0
#9  0x007cb471 in __pthread_unwind () from /lib/libpthread.so.0
#10 0x007c347a in sigcancel_handler () from /lib/libpthread.so.0
#11 <signal handler called>
#12 0xffffe410 in __kernel_vsyscall ()
#13 0x0064decb in semop () from /lib/libc.so.6
#14 0xe0245901 in sqloSSemP () from /opt/IBM/db2/V9.1/lib32/libdb2.so.1
#15 0xe01e7f3c in sqlccipcrecv(sqlcc_comhandle*, sqlcc_cond*) () from /opt/IBM/db2/V9.1/lib32/libdb2.so.1
#16 0xe03fe135 in sqlccrecv () from /opt/IBM/db2/V9.1/lib32/libdb2.so.1
#17 0xe02a0307 in sqljcReceive(sqljCmnMgr*) () from /opt/IBM/db2/V9.1/lib32/libdb2.so.1
#18 0xe02d0ba3 in sqljrReceive(sqljrDrdaArCb*, db2UCinterface*) () from /opt/IBM/db2/V9.1/lib32/libdb2.so.1
#19 0xe02c510d in sqljrDrdaArExecute(db2UCinterface*, UCstpInfo*) () from /opt/IBM/db2/V9.1/lib32/libdb2.so.1
#20 0xe01392bc in CLI_sqlCallProcedure(CLI_STATEMENTINFO*, CLI_ERRORHEADERINFO*) () from /opt/IBM/db2/V9.1/lib32/libdb2.so.1
#21 0xe00589c7 in SQLExecute2(CLI_STATEMENTINFO*, CLI_ERRORHEADERINFO*) () from /opt/IBM/db2/V9.1/lib32/libdb2.so.1
#22 0xe0050fc9 in SQLExecute () from /opt/IBM/db2/V9.1/lib32/libdb2.so.1
#23 0x080a81f7 in apcd_in_thread_call (in_apcd_arg=0xbc8e8f34) at dcs_db2_execute.c:357
#24 0x007c4912 in start_thread () from /lib/libpthread.so.0
#25 0x0064c60e in clone () from /lib/libc.so.6
内核vsyscall()中的0 0xFFFFFFE410 #/lib/libc.so.6中的raise()中的1 0x0059fe30 #2 0x005a1741位于/lib/libc.so.6中的abort()中 #3 0xdef3f5d7英寸??()来自/usr/lib/libstdc++.so.5 #来自/usr/lib/libstdc++.so.5的std::terminate()中的4 0xdef3f624 #来自/usr/lib/libstdc++.so.5的uuugxx_v0()中的5 0xdef3f44c #6 0x007e1917英寸??()来自/lib/libgcc_.so.1 #7 0x007e1c70 in _Unwind_ForcedUnwind()来自/lib/libgcc_s.so.1 #8 0x007cda46在/lib/libpthread.so.0的_Unwind_ForcedUnwind()中 #9 0x007cb471在/lib/libpthread.so.0的uu pthread_unwind()中 #10/lib/libpthread.so.0中的sigcancel_处理程序()中的0x007c347a #11 #内核vsyscall()中的12 0xFFFFFF410 #13/lib/libc.so.6中的semop()中的0x0064debc #来自/opt/IBM/db2/V9.1/lib32/libdb2.so.1的sqloSSemP()中的14 0xe0245901 #来自/opt/IBM/db2/V9.1/lib32/libdb2.so.1的sqlcciprecv(sqlcc_comhandle*,sqlcc_cond*)()中的15 0xe01e7f3c #来自/opt/IBM/db2/V9.1/lib32/libdb2.so.1的sqlccrecv()中的16 0xe03fe135 #来自/opt/IBM/db2/V9.1/lib32/libdb2.so.1的sqljcReceive(sqljCmnMgr*)()中的17 0xe02a0307 #来自/opt/IBM/db2/V9.1/lib32/libdb2.so.1的sqljrReceive(sqljrDrdaArCb*,db2UCinterface*)()中的18 0xe02d0ba3 #来自/opt/IBM/db2/V9.1/lib32/libdb2.so.1的SQLJRDDAARExecute(db2UCinterface*,UCstpInfo*)()中的19 0xe02c510d #来自/opt/IBM/db2/V9.1/lib32/libdb2.so.1的CLI_sqlCallProcedure(CLI_STATEMENTINFO*,CLI_ERRORHEADERINFO*)()中的20 0xe01392bc #来自/opt/IBM/db2/V9.1/lib32/libdb2.so.1的SQLExecute2(CLI_STATEMENTINFO*,CLI_ERRORHEADERINFO*)()中的21 0xe00589c7 #22/opt/IBM/db2/V9.1/lib32/libdb2.so.1中SQLExecute()中的0xe0050fc9 #23 dcs_db2_execute.c:357上apcd_in_thread_调用(in_apcd_arg=0xbc8e8f34)中的0x080a81f7 #/lib/libpthread.so.0的start_thread()中的24 0x007c4912 #从/lib/libc.so.6克隆()中的25 0x0064c60e
异步线程取消只能安全地用于执行非常有限的一组操作的线程-官方规则很长且容易混淆,但实际上,接受异步取消的线程只能执行纯计算。它们不能进行I/O操作,不能分配内存,不能使用任何类型的锁,也不能调用任何可能执行上述任何操作的库函数。对与数据库对话的线程应用异步取消是不安全的

延迟取消限制较少,但仍然非常挑剔。如果您的数据库库没有编码以应对调用线程可能在操作过程中被取消的可能性,那么您也不能安全地使用延迟取消

您需要找到一些其他机制来中止运行时间过长的查询

EDIT:由于这是DB2和名称混乱的“CLI”API,请尝试使用在准备好的语句上设置
SQL\u ATTR\u QUERY\u TIMEOUT
参数,和


编辑之子:据一位比我做了更多数据库工作的朋友说,很可能存在一种服务器端机制,可以取消慢查询,而不管其来源如何。如果DB2中存在这种情况,那么它可能比在客户端手动设置所有查询的超时更方便,特别是因为它可以记录慢速查询,以便您知道它们是哪些查询,并可以对它们进行优化。

因为数据库客户端代码的编写方式可能不足以处理取消(大多数库代码不是),我认为这种方法行不通。有关详细信息,请参阅Zack的答案

如果您需要能够取消数据库连接,则可能必须代理连接并终止代理。基本上,您要做的是创建第二个线程,侦听端口并将连接转发到数据库服务器,并指示数据库客户端连接到本地主机上的此端口,而不是真正的数据库ase服务器/端口。然后可以取消代理线程(使用正常的延迟取消,而不是异步),使用取消清理处理程序关闭套接字。通过关闭的套接字(而不仅仅是非响应套接字)断开与数据库服务器的连接应该导致数据库客户端库代码返回错误,然后您也可以让其线程退出

在设置此类代理时,请记住,您需要确保在访问数据库时不会引入安全问题

以下是可用于代理的代码草图,无需任何错误检查逻辑,也无需考虑意外客户端连接:

int s, c;
struct addrinfo *ai;
struct sockaddr_in sa;
char portstr[8];
getaddrinfo(0, 0, &(struct addrinfo){ .ai_flags = AI_PASSIVE, .ai_family = AF_INET }, &ai);
s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
bind(s, ai->ai_addr, ai_addrlen);
freeaddrinfo(ai);
getsockname(s, (void *)&sa, &(socklen_t){sizeof sa});
port = ntohs(sa.sin_port);
/* Here, do something to pass the port (assigned by kernel) back to the caller. */
listen(s, 1);
c = accept(s, &sa, &(socklen_t){sizeof sa});
close(s);
getaddrinfo("dbserver", "dbport", 0, &ai);
s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
connect(s, ai->ai_addr, ai->ai_addrlen);
freeaddrinfo(ai);
此时,您有两个套接字,
s
连接到数据库服务器,
c
连接到程序另一个线程中的数据库客户端。从一个线程读取的任何内容都应写入另一个;使用
poll
检测哪一个已准备好读取或写入

在上述设置代码期间,除了在
接受
连接
调用周围之外,应该阻止取消,在这些点上,如果发生取消,您需要适当的清理处理程序来关闭套接字并调用
freeaddrinfo
。从
getaddrinfo到本地变量,这样您就可以在阻塞调用之前
freeaddrinfo