zoukankan      html  css  js  c++  java
  • thread.md

    多线程

    Hello world线程

    1. 线程创建pthread_create()

      int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                                void *(*start_routine) (void *), void *arg);
          /*
          一个线程变量名,被创建线程的标识
          线程的属性指针,缺省为NULL即可
          被创建线程的程序代码
          程序代码的参数,For example: - pthread_t thrd1; - pthread_attr_t *attr; - void thread_function(void *argument); - char *some_argument;
          */
      
    2. 线程结束pthread_exit()

      pthread_exit(void *retval);
      // pthread_exit函数唯一的参数value_ptr是函数的返回代码,只要pthread_join中的第二个参数value_ptr不是NULL,这个值将被传递给value_ptr。
      
    3. 线程等待 pthread_join()
      int pthread_join( pthread_t  thread, void * * value_ptr );
      // 阻塞函数,调用它的函数将一直等到被等待的线程结束为止。如果value_ptr不为NULL,那么线程thread的返回值存储在该指针指向的位置。该返回值可以是由pthread_exit给出的值,或者该线程被取消而返回PTHREAD_CANCELED。
      

    实例

    #include <stdio.h>
    #include <pthread.h>
    
    void *print_msg_thread(void *ptr);
    
    int main(void)
    {
        pthread_t t1, t2;
        char msg1[] = "One", msg2[] = "Two";
    
        if (pthread_create(&t1, NULL, print_msg_thread,msg1) == 0){
            printf("线程1创建成功\n");
        }else{
            printf("线程1创建失败");
        }
        if (pthread_create(&t2, NULL, print_msg_thread,msg2) == 0){
            printf("线程2创建成功\n");
        }else{
            printf("线程2创建失败");
        }
    
        void *retval;
        int tmp1, tmp2;
    
        tmp1 = pthread_join(t1, &retval);
        printf("thread1 return value(retval) %p\n", retval);
        printf("thread1 return value(tmp) is %d\n", tmp1);
        printf("thread1 end\n");
    
        tmp2 = pthread_join(t2, &retval);
        printf("thread2 return value(retval) %p\n",             retval);
        printf("thread2 return value(tmp) is %d\n", tmp2);
        printf("thread2 end\n");
    
        return 0;
    }
    void *print_msg_thread(void *ptr)
    {
        for (int i = 0; i < 5; i++)
        {
            printf("%s: %d\n", ptr, i);
        }
        
    }
    

    多线程的同步与互斥

    1. 创建

      • 静态创建: POSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER来静态初始化互斥锁,方法如下:

        pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

      • 动态创建: pthread_mutex_init()函数来初始化互斥锁

        int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)

        mutuex用于指定锁的属性

        互斥锁的属性在创建锁的时候指定,在LinuxThreads实现中仅有一个锁类型属性,不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。当前(glibc2.2.3,linuxthreads0.9)有四个值可供选择:

        Name 简述 介绍
        PTHREAD_MUTEX_TIMED_NP 缺省值,普通锁 当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。
        PTHREAD_MUTEX_RECURSIVE_NP 嵌套锁 允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。
        PTHREAD_MUTEX_ERRORCHECK_NP 检错锁 如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样保证当不允许多次加锁时不出现最简单情况下的死锁。
        PTHREAD_MUTEX_ADAPTIVE_NP 适应锁 动作最简单的锁类型,仅等待解锁后重新竞争
    2. 销毁

      pthread_mutex_destroy()用于注销一个互斥锁,API定义如下:

      int pthread_mutex_destroy(pthread_mutex_t *mutex)

      ​ 销毁一个互斥锁即意味着释放它所占用的资源,且要求锁当前处于开放状态。由于在Linux中,互斥锁并不占用任何资源,因此LinuxThreads中的 pthread_mutex_destroy()除了检查锁状态以外(锁定状态则返回EBUSY)没有其他动作。

    3. 其他

       锁操作主要包括加锁pthread_mutex_lock()、解锁pthread_mutex_unlock()和测试加锁 pthread_mutex_trylock()三个,不论哪种类型的锁,都不可能被两个不同的线程同时得到,而必须等待解锁。对于普通锁和适应锁类型,解锁者可以是同进程内任何线程;而检错锁则必须由加锁者解锁才有效,否则返回EPERM;对于嵌套锁,文档和实现要求必须由加锁者解锁,但实验结果表明并没有这种限制,这个不同目前还没有得到解释。在同一进程中的线程,如果加锁后没有解锁,则任何其他线程都无法再获得锁。
      

        int pthread_mutex_lock(pthread_mutex_t *mutex)
        int pthread_mutex_unlock(pthread_mutex_t *mutex)
        int pthread_mutex_trylock(pthread_mutex_t *mutex)

        pthread_mutex_trylock()语义与pthread_mutex_lock()类似,不同的是在锁已经被占据时返回EBUSY而不是挂起等待。

    4. 死锁

      总体来讲, 有几个不成文的基本原则:

      • 共享资源操作前一定要获得锁。
      • 完成操作以后一定要释放锁。
      • 尽量短时间地占用锁。
      • 如果有多锁, 如获得顺序是ABC连环扣, 释放顺序应该是CBA。
      • 线程错误返回时应该释放它所获得的锁。

    信号量

    /usr/include/semaphore.h中进行定义的,信号量的数据结构为sem_t, 本质上,它是一个long型整数

    1. 初始化

      int sem_init(sem_t *sem, int pshared, unsigned int value);

      返回值: 成功0, 失败-1, errno被设置

      参数:

      • sem,信号地址
      • pshared: 不是0的时候,该信号量在进程间共享,否则只能为当前进程的所有线程们共享
      • value:信号量的初始值
    2. 信号量操作

      int sem_wait(sem_t *sem) //信号减一,信号 == 1 时,会阻塞

      int sem_post(sem_t *sem)//信号+1

    3. 销毁

      int sem_destroy(sem_t *sem);

  • 相关阅读:
    CSS 3 中的多列属性
    CSS3 3D转换
    CC3中的2D转换
    ubuntu sudo: pip:找不到命令
    ubuntu 下更新pip后发生 ImportError: cannot import name 'main'的问题解决
    ubuntu 安装pip
    gradle下载
    L0,L1,L2正则化浅析
    安装使用离线版本的维基百科(Wikipedia)
    Linux中CPU亲和性(affinity)
  • 原文地址:https://www.cnblogs.com/nsfoxer/p/14348118.html
Copyright © 2011-2022 走看看