zoukankan      html  css  js  c++  java
  • Linux 操作系统学习之线程

    Linux在用fork创建进程时,为子进程申请了堆栈、BSS区、全局变量、和代码段等资源。而用pthread_create创建线程时,用户空间分配的资源比线程少得多。可以说,线程就是轻量级的进程。

    1.函数 pthread_create()用来创建一个新的线程。其函数声明如下:

    1 /*come from /usr/include/pthread.h*/
    2 extern int pthread_create (pthread_t *__restrict __newthread,
    3                __const pthread_attr_t *__restrict __attr,
    4                void *(*__start_routine) (void *),
    5                void *__restrict __arg) __THROWNL __nonnull ((1, 3));

    第一个参数用来存储线程的ID,参数为指向线程ID的指针。创建成功,返回新线程ID;_restrict 是C99定义的新标准关键字,主要用来提高编译效率。

    第二个参数用来设置线程属性,主要设置与栈相关的属性。一般情况下,此参数设置为NULL,新的线程将使用系统默认的属性。

    第三个参数是线程运行的代码起始地址。

    第四个参数是运行函数的参数地址,如果需要传入多个参数,需要使用结构体。

    示例:

     1 #include <pthread.h>
     2 #include <stdio.h>
     3 #include <stdlib.h>
     4 #include <string.h>
     5 #include <unistd.h>
     6 #include <sys/syscall.h>
     7 
     8 struct message
     9 {
    10     int i;
    11     int j;
    12 };
    13 
    14 void *hello (struct message *str);
    15 
    16 int main(int argc, char* argv[])
    17 {
    18     struct message test;
    19     pthread_t thread_id;
    20     test.i = 10;
    21     test.j = 20;
    22     /*create thread*/
    23     pthread_create(&thread_id, NULL, (void *) *hello, &test);
    24     printf("parent, the tid = %lu, pid = %ld
    ",pthread_self(),syscall(SYS_gettid));
    25     pthread_join(thread_id,NULL);
    26     sleep(1);
    27     return 0;
    28 }
    29 
    30 void *hello (struct message *str)
    31 {
    32     printf("child, the tid = %lu, pid = %ld
    ",pthread_self(),syscall(SYS_gettid));
    33     printf("the arg.i is %d, arg.j is %d
    ",str->i, str->j);
    34 }

     2.线程的退出和等待:

    线程的退出函数声明如下:

    extern void pthread_exit (void *__retval) __attribute__ ((__noreturn__));

    此函数只有一个参数,即线程退出状态。

    等待线程:

    为了同步线程,一般主线程都会等待子线程结束,显式的等待某线程结束。可以调用pthread_join实现。其函数声明如下:

    extern int pthread_join (pthread_t __th, void **__thread_return);

    第一个参数是被等待的线程的ID,第二个参数为用户定义的指针,指向一个保存等待线程的完整退出状态的静态区域,它可以用来存储被等待线程的返回值。

    线程的独立:

    如果要设置某个线程为独立线程,则可以调用pthread_detach实现。声明如下:

    extern int pthread_detach (pthread_t __th) 

    示例代码:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <pthread.h>
     4 #include <string.h>
     5 #include <unistd.h>
     6 #include <sys/syscall.h>
     7 
     8 void *helloworld(char* arg);
     9 
    10 int main(int argc, char* argv[])
    11 {
    12     int error;
    13     int *temptr;
    14     pthread_t thread_id;
    15     /*create thread*/
    16     pthread_create(&thread_id,NULL,(void)helloworld,"hello,world");
    17     printf("*p = %u, p = %u
    ",(unsigned int)*helloworld,(unsigned int) helloworld);
    18     
    19     /*wait for child thread terminating*/
    20     pthread_join(thread_id,(void **)&temptr);
    21 
    22     printf("temp = %x, *temp = %c
    ",(unsigned)temptr,*temptr);
    23     *temptr = 'd';
    24     printf("%c
    ",*temptr);
    25     free(temptr);
    26     return 0;
    27 }
    28 
    29 void *helloworld(char *arg)
    30 {
    31     int *p;
    32     p = (int*)malloc(10*sizeof(int));
    33     printf("the message is %s
    ",arg);
    34     printf("the child id is %u
    ",pthread_self());
    35     memset(p,'c',10);
    36     printf("p = %x
    ",(unsigned)p);
    37     /*thread exit*/
    38     pthread_exit(p);
    39 }
    View Code

    3.线程退出前的操作
    线程的终止会存在资源释放的问题。经常出现的情形:线程为了访问临界资源而为其上锁,但访问过程中该线程被取消,如果线程响应取消,那么临界资源得不到释放。pthread_cleanup_push()/pthread_cleanup_pop()函数用来自动释放资源。其声明如下:

    void pthread_cleanup_push(routine, arg)
    void pthread_cleanup_pop(execute)

    当线程退出时,可以先执行线程处理程序。

    示例代码:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <pthread.h>
     4 #include <unistd.h>
     5 
     6 void cleanup()
     7 {
     8     printf("clean up
    ");
     9 }
    10 
    11 void *test_cancel(void)
    12 {
    13     pthread_cleanup_push(cleanup,NULL);
    14     printf("test_cancel
    ");
    15     while(1)
    16     {
    17         printf("test message
    ");
    18         sleep(1);
    19     }
    20     pthread_cleanup_pop(1);
    21 }
    22 
    23 int main()
    24 {
    25     pthread_t tid;
    26     pthread_create(&tid,NULL,(void*)test_cancel,NULL);
    27     sleep(4);
    28     pthread_cancel(tid);
    29     pthread_join(tid,NULL);
    30     return 0;
    31 }
    View Code

    4.取消线程:

    函数声明:

    /* Cancel THREAD immediately or at the next possibility.  */
    extern int pthread_cancel (pthread_t __th);

    pthread_cancel 函数请求取消线程。只有当目标线程为可取消状态为PTHREAD_CANCEL_ENABLE时,才可被取消。执行取消操作时,将调用线程的取消清理处理程序(pthread_cleanup_push函数)。而pthread_cancel 的调用者不会等待目标线程操作完成。

    设置可取消状态:

    pthread_setcancelstate()和pthread_setcanceltype()可以用来设置和查询当前线程的可取消性状态或类型。函数声明分别如下:

    1 /* Set cancelability state of current thread to STATE, returning old
    2    state in *OLDSTATE if OLDSTATE is not NULL.  */
    3 extern int pthread_setcancelstate (int __state, int *__oldstate);
    4 
    5 /* Set cancellation state of current thread to TYPE, returning the old
    6    type in *OLDTYPE if OLDTYPE is not NULL.  */
    7 extern int pthread_setcanceltype (int __type, int *__oldtype);

    对于pthread_setcancelstate,该函数有两个参数,state是要设置的新的状态;oldstate用来存储原来的状态。state的值有:

    PTHREAD_CANCEL_DISABLE,除非该线程修改自己的状态,否则不可被取消

    PTHREAD_CANCEL_ENABLE,这是默认值。

    设置取消类型:

    有两个参数:

    PTHREAD_CANCEL_ASYNCHRONOUS:可随时执行取消请求。

    PTHREAD_CANCEL_DEFFERED: 在取消点取消。

    线程取消的示例:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <unistd.h>
     4 #include <pthread.h>
     5 
     6 void *thread_function(void *arg);
     7 
     8 int main(int argc, char* argv[])
     9 {
    10     //int res;
    11     pthread_t a_thread;
    12     void *thread_result;
    13     pthread_create(&a_thread,NULL,thread_function,NULL);
    14     sleep(1);
    15     printf("cancelling thread...
    ");
    16     pthread_cancel(a_thread);
    17     printf("wait for thread to finish...
    ");
    18     pthread_join(a_thread,&thread_result);
    19     return 0;
    20 }
    21 
    22 void *thread_function(void *arg)
    23 {
    24     int i;
    25     //sleep(1);
    26     /*set cancel state as disable*/
    27     pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
    28     sleep(3);
    29     printf("thread cancel type is disable cannot cancel this thread
    ");
    30     
    31     for(i = 0;i<3;i++)
    32     {
    33         printf("thread is running (%d)...
    ",i);
    34         sleep(1);
    35     }
    36     pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
    37     printf("Now the cancel state is enable
    ");
    38     sleep(200);
    39     pthread_exit(0);
    40 }
    View Code

    5.线程与私有数据

      5.1

    在多线程程序中,全局变量为所有线程所共享。但有时有必要提供线程私有的全局变量。实现的方法是使用同名却不同内存地址的线程数据结构。这样的数据结构可以由Posix线程库维护,成为线程私有数据TSD(Thread-specific Data)。

    创建、注销线程私有数据:

    extern int pthread_key_create (pthread_key_t *__key,
                       void (*__destr_function) (void *))

    该函数从TSD池中分配一项,将其地址赋值给key供以后使用。如果第二个参数不是空,在线程退出时将以key所提供的数据作为参数调用其指向的资源释放函数,以释放分配的缓冲区。

    用pthread_key_create()创建的key都是所有线程可以访问的,但是各个线程可以根据自己的需要修改key,而不影响其他线程的key值。

    注销一个TSD:

    extern int pthread_key_delete (pthread_key_t __key)

    读写线程的私有数据:

    extern int pthread_setspecific (pthread_key_t __key,
                    __const void *__pointer)
    extern void *pthread_getspecific (pthread_key_t __key)

    pthread_setspecific将pointer的值与key关联。

    pthread_getspecific 将key与相关连的数据读出,数据类型设为void*因此可以指向任何类型。

    应用示例:

    全局变量,数据共享

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <unistd.h>
     4 #include <pthread.h>
     5 #include <sys/types.h>
     6 
     7 int key = 100;
     8 
     9 void *helloworld_one(char* arg);
    10 void *helloworld_two(char* arg);
    11 
    12 int main(int argc, char* argv[])
    13 {
    14 
    15     pthread_t thread_id_one;
    16     pthread_t thread_id_two;
    17     pthread_create(&thread_id_one,NULL,(void*)helloworld_one,"hello,world one");
    18     pthread_create(&thread_id_two,NULL,(void*)helloworld_two,"hello,world two");
    19     pthread_join(thread_id_one,NULL);
    20     pthread_join(thread_id_two,NULL);
    21     return 0;
    22 }
    23 
    24 void *helloworld_one(char *arg)
    25 {
    26     printf("this is thread one, the arg is %s
    ",arg);
    27     printf("the key is %d
    ",key);
    28     key++;
    29     printf("now the key++ has been excuted
    ");
    30     pthread_exit(0);
    31 }
    32 void *helloworld_two(char *arg)
    33 {
    34     sleep(1);
    35     printf("this is thread two, the arg is %s
    ",arg);
    36     printf("the key is %d
    ",key);
    37     pthread_exit(0);
    38 }
    View Code

    全局变量,私有数据

     1 #include <stdio.h>
     2 #include <pthread.h>
     3 #include <stdlib.h>
     4 #include <unistd.h>
     5 
     6 pthread_key_t key;/*线程私有数据类型*/
     7 
     8 void echomsg(void *t)
     9 {
    10     printf("destructor excuted in thread %u, param = %u
    ",pthread_self(),((int*)t));
    11 }
    12 void *child_one(void *arg)
    13 {
    14     int i = 10;
    15     int tid = pthread_self();
    16     printf("set key value %d in thread %u
    ",i,tid);
    17     /*modify the value of key*/
    18     pthread_setspecific(key,&i);
    19     /*等待线程二修改值*/
    20     printf("thread one sleep 2 until thread two finish
    ");
    21     sleep(2);
    22     /*print the current value of the thread*/
    23     printf("thread %u return %d, add is %u
    ",tid, *((int*)pthread_getspecific(key)),(int*)pthread_getspecific(key));    
    24 }
    25 void *child_two(void *arg)
    26 {
    27     int i = 20;
    28     int tid = pthread_self();
    29     printf("set key value %d in thread %u
    ",i,tid);
    30     /*modify the value of key*/
    31     pthread_setspecific(key,&i);
    32     printf("thread two sleep 1 
    ");
    33     sleep(1);
    34     /*print the current value of the thread*/
    35     printf("thread %u return %d, add is %u
    ",tid, *((int*)pthread_getspecific(key)),(int*)pthread_getspecific(key));    
    36 }
    37 int main(void)
    38 {
    39     pthread_t tid1,tid2;
    40     pthread_key_create(&key,echomsg);
    41     pthread_create(&tid1,NULL,(void*)child_one,NULL);    
    42     pthread_create(&tid2,NULL,(void*)child_two,NULL);
    43     pthread_join(tid1,NULL);
    44     pthread_join(tid2,NULL);
    45     pthread_key_delete(key);
    46     return 0;
    47 }
    View Code
  • 相关阅读:
    python struct使用
    pythonunittest(1)
    python os.path模块学习(转)
    pythonunittest(2)
    主机+虚拟机Ubuntu+开发板互相ping通
    wince 外部中断调用可安装ISR错误(data abort)
    wince firstboot.nb0 的大小的问题解决
    wince 串口索引超过10个解决方法
    wince uboot 启动 wince
    zigbee 天线的设计
  • 原文地址:https://www.cnblogs.com/yongjiuzhizhen/p/3467336.html
Copyright © 2011-2022 走看看