• tinycthread


    互斥锁声明

    typedef struct {
      union {
        CRITICAL_SECTION cs;      /* Critical section handle (used for non-timed mutexes) */
        HANDLE mut;               /* Mutex handle (used for timed mutex) */
      } mHandle;                  /* Mutex handle */
      int mAlreadyLocked;         /* TRUE if the mutex is already locked */
      int mRecursive;             /* TRUE if the mutex is recursive */
      int mTimed;                 /* TRUE if the mutex is timed */
    } mtx_t;

     互斥锁简介:

    作用:保证共享数据操作的完整性,每个对象都有一个互斥锁的标记,

               用来保证任意时刻,只有一个线程访问改对象。

    创建与销毁:创建声明互斥锁类型;销毁要求锁是开放状态才能释放资源,在linux中互斥锁不占用资源,只检查锁状态。

    互斥锁属性(创建锁时指定):

    类型 锁名 功能
    PTHREAD_MUTEX_TIMED_NP 普通锁 当一个线程加锁后,其余线程形成一个等待队列,解锁后按照优先级访问获得锁
    PTHREAD_MUTEX_RECURSIVE_NP 嵌套锁 允许同一线程对同一个锁成功获得多次,并通过unlock解锁;不同线程则解锁时重新竞争(存在计数器存储访问数量 访问为0时清空)
    PTHREAD_MUTEX_ERRORCHECK_NP 检错锁

    同一线程请求同一个锁返回EDEADLK,否则与普通锁相同

    PTHREAD_MUTEX_ADAPTIVE_NP 适应锁 动作简单 等待解锁后重新竞争

    锁操作:

    1.加锁

    2.解锁

    3.测试加锁

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

    tinycthread

    互斥锁类型:
    类型 说明  
    mtx_plain 普通锁  
    mtx_recursive 递归锁(同一线程可调用多次)  
    mtx_timed 普通锁并且支持超时  
    使用:
     
    1.mtx_plain:普通锁
    2.mtx_timed:普通超时锁
    3.mtx_plain & mtx_recursive:普通可递归锁
    4.mtx_timed & mtx_recursive:普通可超时递归锁
     
    函数说明:

    1.初始化锁(返回成功/失败)

    int mtx_init(mtx_t *mtx, int type) //输入以上三种type中一个
    {
    #if defined(_TTHREAD_WIN32_) //win下创建
      mtx->mAlreadyLocked = FALSE;
      mtx->mRecursive = type & mtx_recursive;
      mtx->mTimed = type & mtx_timed;
      if (!mtx->mTimed) //非可超时锁时声明
      {
        InitializeCriticalSection(&(mtx->mHandle.cs));
      }
      else
      {
        mtx->mHandle.mut = CreateMutex(NULL, FALSE, NULL); //创建一把锁
        if (mtx->mHandle.mut == NULL)
        {
          return thrd_error;
        }
      }
      return thrd_success;
    #else //linux下创建
      int ret;
      pthread_mutexattr_t attr;//生成一个linux下的
      pthread_mutexattr_init(&attr);
      if (type & mtx_recursive)
      {
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
      }
      ret = pthread_mutex_init(mtx, &attr);
      pthread_mutexattr_destroy(&attr);
      return ret == 0 ? thrd_success : thrd_error;
    #endif
    }

    时间锁

    int mtx_timedlock(mtx_t *mtx, const struct timespec *ts)

    参数:线程锁主体与时间空间(含秒与纳秒两个参数)

    int mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
    {
    #if defined(_TTHREAD_WIN32_)
      struct timespec current_ts;
      DWORD timeoutMs;
    
      if (!mtx->mTimed)
      {
        return thrd_error;
      }
    
      timespec_get(&current_ts, TIME_UTC);
    
      if ((current_ts.tv_sec > ts->tv_sec) || ((current_ts.tv_sec == ts->tv_sec) && (current_ts.tv_nsec >= ts->tv_nsec)))
      {
        timeoutMs = 0;
      }
      else
      {
        timeoutMs  = (DWORD)(ts->tv_sec  - current_ts.tv_sec)  * 1000;
        timeoutMs += (ts->tv_nsec - current_ts.tv_nsec) / 1000000;
        timeoutMs += 1;
      }
    
      /* TODO: the timeout for WaitForSingleObject doesn't include time
         while the computer is asleep. */
      switch (WaitForSingleObject(mtx->mHandle.mut, timeoutMs))
      {
        case WAIT_OBJECT_0:
          break;
        case WAIT_TIMEOUT:
          return thrd_timedout;
        case WAIT_ABANDONED:
        default:
          return thrd_error;
      }
    
      if (!mtx->mRecursive)
      {
        rd_assert(!mtx->mAlreadyLocked); /* Would deadlock */
        mtx->mAlreadyLocked = TRUE;
      }
    
      return thrd_success;
    #elif defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS >= 200112L) && defined(_POSIX_THREADS) && (_POSIX_THREADS >= 200112L)//linux下自带timedlock可调用情况
      switch (pthread_mutex_timedlock(mtx, ts)) {
        case 0:
          return thrd_success;
        case ETIMEDOUT:
          return thrd_timedout;
        default:
          return thrd_error;
      }
    #else //手动实现一个lock
      int rc;
      struct timespec cur, dur;
    
      /* Try to acquire the lock and, if we fail, sleep for 5ms. */
      while ((rc = pthread_mutex_trylock (mtx)) == EBUSY) {
        timespec_get(&cur, TIME_UTC);
    
        if ((cur.tv_sec > ts->tv_sec) || ((cur.tv_sec == ts->tv_sec) && (cur.tv_nsec >= ts->tv_nsec)))
        {
          break;
        }
    
        dur.tv_sec = ts->tv_sec - cur.tv_sec;
        dur.tv_nsec = ts->tv_nsec - cur.tv_nsec;
        if (dur.tv_nsec < 0)
        {
          dur.tv_sec--;
          dur.tv_nsec += 1000000000;
        }
    
        if ((dur.tv_sec != 0) || (dur.tv_nsec > 5000000))
        {
          dur.tv_sec = 0;
          dur.tv_nsec = 5000000;
        }
    
        nanosleep(&dur, NULL);
      }
    
      switch (rc) {
        case 0:
          return thrd_success;
        case ETIMEDOUT:
        case EBUSY:
          return thrd_timedout;
        default:
          return thrd_error;
      }
    #endif
    }

     背景

    linux下线程通信方法:互斥锁,条件变量,信号量,读写锁

    互斥锁

    同一时刻只允许一个线程执行一个关键部分的代码

    linux下pthread互斥锁函数

    linux下互斥锁类型

     

    按照系统分类直接调用系统下线程处理模块函数:
    线程销毁 void mtx_destroy(mtx_t *mtx) 
    线程加锁  int mtx_lock(mtx_t *mtx)
    尝试锁 int mtx_trylock(mtx_t *mtx)
    解锁 int mtx_unlock(mtx_t *mtx)
     

    条件变量

     
     
    利用线程间共享全局变量进行同步的一种机制。条件变量上的基本操作有:触发条件(当条件变为 true 时);等待条件,挂起线程直到其他线程触发条件
    1.创建条件变量   pthread_cond_init(cond, NULL)
    2.销毁条件变量   pthread_cond_destroy(cond)
    3.激活等待该条件的线程(多个等待线程按顺序激活一个) pthread_cond_signal(cond)
    4.广播激活所有等待条件线程 pthread_cond_broadcast(cond)
    5.自动解锁互斥量,并等待条件变量触发 pthread_cond_wait(cond, mtx)     pthread_cond_wait()  函数一进入wait状态就会自动release mutex
                                                                                                                           pthread_cond_wait()通过(返回)时,该线程又自动获得该 mutex
    6.超时条件触发 pthread_cond_timedwait
     

    线程操作

    1.线程创建:pthread_create

    第一个参数为指向线程标识符的指针, 在程序中我们传递p的地址进去.
    第二个参数为线程的属性. 默认传递NULL就可以. 线程的属性有很多, 比如可以设置线程调度的优先级, 比如可以设置线程栈的大小. 可以看看这篇博客
    第三个参数是线程要执行的函数指针. 从函数原型上看, 这个函数的类型只能是void *
    第四个参数是函数的参数. 从函数原型上看, 参数的类型只能是void *. 但我们知道void *类型是可以转换为其他类型的, 所以在这个函数内部进行类型转换即可. 如果有多个参数需要传递, 就定义一个结构体

    2.线程等待pthread_join(thr, &pres)

    ...

     

  • 相关阅读:
    paddlex 使用-7 windows下脚本生成nb文件
    paddlex 使用-6 在Android下预测
    paddlex 使用-5 Andrdroid4.1报错插件无法删除
    paddlex 使用-4 format = EXTENSION[ext].6错误
    paddlex 使用-3 模型加载预测
    paddlex 使用-2 GUI版本
    paddlex 使用-1 安装
    企业微信登录态与显示姓名
    计算工龄(月份)的C#算法
    一个比较好用的Mongodb 工具
  • 原文地址:https://www.cnblogs.com/supermanwx/p/16056167.html
Copyright © 2020-2023  润新知