• (转)Linux 多线程编程---pthread_testcancel()等讲解


    1.   所谓线程就是“一个进程内部的一个控制序列”。也就是一个进程内部的并行的基础!

    2.    Linux进程可以看成只有一个控制线程:
          一个进程在同一时刻只做一件事情。有了多个控制线程以后,
          在程序设计时可以把进程设计成在同一时刻能够做不止一件事,
          每个线程处理各只独立的任务。即所谓并行!
         
    3.     线程的优点:
              (1)通过为每种事件类型的处理分配单独的线程,能够简化处理异步时间的代码。
              (2)多个线程可以自动共享相同的存储地址空间和文件描述符。
              (3)有些问题可以通过将其分解从而改善整个程序的吞吐量。
              (4)交互的程序可以通过使用多线程实现相应时间的改善,多线程可以把程序中
                   处理用户输入输出的部分与其它部分分开。

    4.       线程的缺点:
             线程也有不足之处。编写多线程程序需要更全面更深入的思考。
             在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的
             变量而造成不良影响的可能性是很大的。调试一个多线程程序也
             比调试一个单线程程序困难得多。     
         
    5.    线程标识:
          我们已经知道进程有进程ID就是pid_t,那么线程也是有自己的ID的pthread_t数据类型!
          注意:实现的时候可以用一个结构来代表pthread_t数据类型,所以可以移植的操作系统
                不能把它作为整数处理。因此必须使用函数来对来对两个线程ID进行比较。
         
    6.    pthread_cancel:取消同一进程中的其他线程(注意是取消其他线程)
         
           intpthread_cancel(pthread_t tid);
          若成功返回0,否则返回错误编号。
          注意:pthread_cancel并不等待线程终止,它仅仅提出请求。是否真的执行还看目标线程的
                state和type的设置了!
         
    7.  pthread_cleanup_push 和pthread_cleanup_pop:线程清理处理程序     
         
           voidpthread_cleanup_push( void ( * rtn ) ( void * ),void *arg );
           voidpthread_cleanup_pop( int exe );
           参数:
                rtn:  处理程序入口地址
                 arg:传递给处理函数的参数
          线程可以安排它退出时需要调用的函数,这样的函数称为线程清理处理程序,线程可以建立多个清理处理程序。
          注意:此处是使用栈保存的,所以是先进后处理原则!
                如果线程是通过从启动例程中返回而终止的,它的处理程序就不会调用。
         
          !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
          ATTENTION:
                      pthread_cleanup_push注册一个回调函数,如果你的线程在对应的pthread_cleanup_pop
                      之前异常退出(return是正常退出,其他是异常),那么系统就会执行这个回调函数(回调函
                      数要做什么你自己决定)。但是如果在pthread_cleanup_pop之前没有异常退出,
                      pthread_cleanup_pop就把对应的回调函数取消了,
         
           所以请注意:
                只有在“清理函数”的设置和取消之间有异常的退出,才会调用我们设置的“清理函数”。
                否则是不会输出的!
                一般的触发条件是:在之间有pthread_exit(非正常退出);或者有取消点时候!
               
           关于“取消点” (cancellation point ):
                例如执行下面代码:
                                printf("sleep ");
                                sleep(10);
                                 printf("wake ");
          在sleep函数中,线程睡眠,结果收到cancel信号,这时候线程从sleep中醒来,但是线程不会立刻退出。
          >>>>>:     
                函数:pthread_testcancel():
                描述:函数在运行的线程中创建一个取消点,如果cancellation无效则此函数不起作用。
                
                pthread的建议是:如果一个函数是阻塞的,那么你必须在这个函数前后建立 “ 取消点 ”, 比如:
                                printf("sleep ");
                               pthread_testcancel();
                                sleep(10);
                                pthread_testcancel();
                                 printf("wake ");
                在执行到pthread_testcancel的位置时,线程才可能响应cancel退出进程
               
                对于一些函数来说本身就是有cancellation point 的,那么可以不管,但是大部分还是没有的,
                所以要使用pthread_testcancel来设置一个取消点,那么也并不是对于所有的函数都是有效的,
                对于有延时的函数才是有效的,更清楚的说是有时间让pthread_cancel响应才是OK的!
               
           附加:
                POSIX中的函数cancellation点的:
                pthread_join
                pthread_cond_wait
                thread_cond_timewait
                pthread_testcancel
                sem_wait
                sigwait       都是cancellation点.
                下面的这些系统函数也是cancellation点:
                 accept
                 fcntl
                 open
                 read
                 write
                 lseek
                 close
                 send
                sendmsg
                 sendto
                connect
                 recv
                recvfrom
                recvmsg
                 system
                tcdrain
                 fsync
                 msync
                 pause
                 wait
                waitpid
                nanosleep
     
                其它的一些函数如果调用了上面的函数, 那么, 它们也是cancellation点.
                 intpthread_setcancelstate (int STATE, int *OLDSTATE);
                用于允许或禁止处理cancellation,
                STATE可以是:PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DISABLE

                 intpthread_setcanceltype (int TYPE, int *OLDTYPE);
                设置如何处理cancellation, 异步的还是推迟的.
                TYPE可以是:PTHREAD_CANCEL_ASYNCHRONOUS, PTHREAD_CANCEL_DEFERRED
                  
          >>>>        
          摘录:http://blogt.chinaunix.net/space.php?uid=23381466&do=blog&id=58787

                什么是取消点(cancelation point)?

                资料中说,根据POSIX标准,pthread_join()、pthread_testcancel()、pthread_cond_wait()、
                pthread_cond_timedwait()、sem_wait()、sigwait()等函数以及read()、write()等会引起阻塞
                的系统调用都是Cancelation-point。而其他pthread函数都不会引起 Cancelation动作。但
                是pthread_cancel的手册页声称,由于LinuxThread库与C库结合得不好,因而目前C库函
                 数都不是Cancelation-point;但CANCEL信号会使线程从阻塞的系统调用中退出,并置
                EINTR错误码,因此可以在需要作为Cancelation-point的系统调用前后调用pthread_testcancel(),
                从而达到POSIX标准所要求的目标,即如下代码段:

                pthread_testcancel();
                 retcode =read(fd, buffer, length);
                pthread_testcancel();

                我发现,对于C库函数来说,几乎可以使线程挂起的函数都会响应CANCEL信号,终止线程,
                包括sleep、delay等延时函数。                    
        本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2012-03/57249p2.htm

    8、示例代码:

    /*
     * ThreadCancel.c
     *
     *  Created on: Aug 17, 2013
     *      Author: root
     */
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <pthread.h>
    #include <errno.h>
    
    #define NUM_THREADS 5
    void* search(void *);
    void print_it(void*);
    
    pthread_t threads[NUM_THREADS];
    pthread_mutex_t lock;
    int tries;
    int started;
    int main(){
        int i, pid;
        pid = getpid();
        printf("Search for the number=%d...
    ", pid);
        pthread_mutex_init(&lock,NULL);
        for(started=0;started<NUM_THREADS; started++){
            pthread_create(&threads[started], NULL, search, (void*)pid);
        }
        for(i=0; i<NUM_THREADS; i++){
            pthread_join(threads[i], NULL);
        }
        printf("It took %d tries to find the number.
    ", tries);
        return 0;
    }
    
    void print_it(void * arg){
        int *try = (int *)arg;
        pthread_t tid;
        tid = pthread_self();
        printf("Thread %lx was canceled on its %d try.
    ", tid, *try);
    }
    
    void * search(void * arg){
        int num = (int)arg;
        int i,j,ntries;
        pthread_t tid;
        tid = pthread_self();
        while(pthread_mutex_trylock(&lock) == EBUSY){
            pthread_testcancel();                            //thread may be canceled and call cancel function handler !
        }
        printf("current thread tid:%lx.
    ", tid);
        srand((int)tid);
        printf("current thread tid:%lx, after srand method.
    ", tid);
        i = rand() & 0xFFFFFF;
        pthread_mutex_unlock(&lock);
        ntries = 0;
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
        while(started < NUM_THREADS){
            sched_yield();
        }
        pthread_cleanup_push(print_it, (void*)&ntries);
        while(1){
            i = (i+1) & 0xffffff;
            ntries++;
            if(num == i){
                while(pthread_mutex_trylock(&lock) == EBUSY){
                    printf("Thread %lx found the number! But not get lock!
    ", tid);
                    pthread_testcancel();
                }
                tries = ntries;
                printf("Thread %lx found the number!
    ", tid);
                for(j=0;j<NUM_THREADS;j++){
                    if(threads[j] != tid){
                        pthread_cancel(threads[j]);
                    }
                }
                break;
            }
    
            if(ntries %100 ==0){
                pthread_testcancel();
            }
        }
    
        pthread_cleanup_pop(0);
        return ((void*)0);
    }

       因为是多线程运行,所以运行结果可能有好几个,运行结果(一):

       

        运行结果(二):

       

  • 相关阅读:
    一个网络扫描程序
    ASCII
    一个linux下c++程序
    VC数字图像处理编程
    人际关系的55个绝招
    一些函数
    【转】Vim命令合集以及乱码问题解决
    【转】PHP程序员的技术成长规划
    【转】Nginx 服务器安装及配置文件详解
    【转】PHP网站常见安全漏洞,及相应防范措施总结
  • 原文地址:https://www.cnblogs.com/wangle1001986/p/3250501.html
Copyright © 2020-2023  润新知