互斥锁声明
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(¤t_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)
...