zoukankan      html  css  js  c++  java
  • linux c 笔记 线程控制(二)

    linux 下有两种方式可以使线程终止,一种是通过调用return 从线程函数返回,第二种是通过调用函数 
    #include
    voidpthread_exit(void *retavl);

    需要注意的地方:一是,主线程中如果从main函数返回或是调用了exit函数退出主线程,则整个进程终止,此时所有的其他线程也将终止。另一种是,如果主线程调用pthread_exit函数,则仅仅是主线程消亡,进程不会结束,其他线程也不会结束,直到所有的线程都结束时,进程才结束。

    线程的分离状态决定一个线程以什么样的方式来终止自己。通常采用了线程的默认属性,即为非分离状态,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。而分离线程不是这样子的,它没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。
    在使用 Pthread 时避免线程的资源在线程结束时不能得到正确释放,从而避免产生潜在的内存泄漏问题,在对待线程结束时,要确保该线程处于 detached 状态,否着就需要调用 pthread_join() 函数来对其进行资源回收。




    私有数据


      进程内的所有线程共享进程的数据空间,所以全局变量为所有线程共有。在某些场景下,线程需要保存自己的私有数据,这时可以创建线程私有数据(Thread-specific Data)TSD来解决。在线程内部,私有数据可以被线程的各个接口访问,但对其他线程屏蔽。

    线程私有数据采用了一键多值技术,及一个key对应多个值。访问数据都是通过键值来访问的。使用线程私有数据时,需要对每个线程创建一个关联 的key,linux中主要有四个接口来实现:

    1、pthread_key_create:创建一个键
    int pthread_key_create(pthread_key_t *key, void (*destr_function) (void*));

    首先从linux的TSD池中分配一项,然后将其值赋给key供以后访问使用。接口的第一个参数是指向参数的指针,第二参数是函数指针,如果该指针不为空,那么在线程执行完毕退出时,已key指向的内容为入参调用destr_function(),释放分配的缓冲区以及其他数据。
    key被创建之后,因为是全局变量,所以所有的线程都可以访问。各个线程可以根据需求往key中,填入不同的值,这就相当于提供了一个同名而值不同的全局变量,即一键多值。一键多值依靠的一个结构体数组,即
    static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] ={{0,NULL}};

    创建一个TSD,相当于将结构体数组的某一个元素的seq值设置为为“in_use”,并将其索引返回给*key,然后设置destr_function()为destr()。pthread_key_create创建一个新的线程私有数据key时,系统会搜索其所在进程的key结构数组,找出一个未使用的元素,将其索引赋给*key。

    2、pthread_setspecific:为指定键值设置线程私有数据
    int pthread_setspecific(pthread_key_t key, const void *pointer);

    该接口将指针pointer的值(指针值而非其指向的内容)与key相关联,用pthread_setspecific为一个键指定新的线程数据时,线程必须释放原有的数据用以回收空间。

    3、pthread_getspecific:从指定键读取线程的私有数据
    void * pthread_getspecific(pthread_key_t key);

    4、pthread_key_delete:删除一个键
    void * pthread_getspecific(pthread_key_t key);

    该接口用于删除一个键,功能仅仅是将该key在结构体数组pthread_keys对应的元素设置为“un_use”,与改key相关联的线程数据是不会被释放的,因此线程私有数据的释放必须在键删除之前。




    互斥锁:
    为了排除竞争条件的影响,应该使一些操作变成“原子的”——这些操作既不能分割也不能中断。
    当一个线程锁定了互斥锁后,其他线程也要求锁定这个互斥锁的时候,就会被阻塞;直到前面的线程解除锁定后,其他线程才可以解除阻塞恢复运行。
    GNU/Linux保证线程在锁定互斥锁的过程中不会发生竞争条件,只有一个线程可以锁定互斥锁,其他线程的锁定请求都会被阻塞。

    创建互斥锁(Mutex),需要:
    创建一个pthread_mutex_t类型的变量,将其指针传入函数pthread_mutex_init中;该函数的第二个参数是指向一个mutex属性对象(这个对象用来指定mutex的属性)的指针。mutex对象只能初始化一次。
    更简单的办法是,使用PTHREAD_MUTEX_INITIALIZER来获得默认属性的mutex对象:
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;


    调用pthread_mutex_lock函数,如果mutex对象未被锁定,则此函数立即返回;如果已被锁定,则此函数阻塞此线程的执行,直到mutex被解除锁定。
    每次解除锁定后,只有一个线程可以解除阻塞恢复执行,其他调用线程都会继续阻塞。选定的解除阻塞的线程是不可预知的。
    调用pthread_mutex_unlock函数,可以解除调用线程对mutex对象的锁定。在锁定mutex的线程中,必须调用此函数以解除锁定。

    函数说明:

    需要的头文件:pthread.h
    1)初始化互斥锁

    函数原型:int  pthread_mutex_init  (pthread_mutex_t   *mp, const pthread_mutex  attr_t *mattr)


    初始化互斥锁之前,必须将其所在的内存清零。

    如果互斥锁已初始化,则它会处于未锁定状态。互斥锁可以位于进程之间共享的内存中或者某个进程的专用内存中。

    2)锁定互斥锁

    函数原型:

    int pthread_mutex_lock(pthread_mutex_t *mutex);
    pthread_mutex_t mutex;

    int ret;
    ret = pthread_ mutex_lock(&mp); /* acquire the mutex */

    函数说明:

    当 pthread_mutex_lock() 返回时,该互斥锁已被锁定。调用线程是该互斥锁的属主。如果该互斥锁已被另一个线程锁定和拥有,则调用线程将阻塞,直到该互斥锁变为可用为止。

  • 相关阅读:
    把影响集中到一个点
    How to avoid Over-fitting using Regularization?
    适定性问题
    Numerical Differentiation 数值微分
    What Every Computer Scientist Should Know About Floating-Point Arithmetic
    Generally a good method to avoid this is to randomly shuffle the data prior to each epoch of training.
    What is the difference between iterations and epochs in Convolution neural networks?
    Every norm is a convex function
    Moore-Penrose Matrix Inverse 摩尔-彭若斯广义逆 埃尔米特矩阵 Hermitian matrix
    perl 类里的函数调用其他类的函数
  • 原文地址:https://www.cnblogs.com/kaylee-lr/p/4691327.html
Copyright © 2011-2022 走看看