- 在代码中使用pthread,进行编译时,需要使用命令 g++ -o hello hello.c -lpthread
- Makefile怎么写?
互斥锁
互斥锁只有两种状态,锁定和非锁定
头文件:<pthread.h>
类型:pthread_mutex_t
- pthread_mutex_lock:加锁。如果锁已经被占有,则该线程加入一个队列中。
- pthread_mutex_trylock:尝试加锁,如果锁已被占有,则线程不加入队列,而是返回错误。
- pthread_mutex_unlock:释放锁
例程
- 5个线程互斥显示数组数字,当其中一个线程在显示时,其他线程无法显示,直接退出
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
// 声明并且初始化锁(互斥锁)
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
int tf[5];
void* print(void* i)
{
/********************************************
* 如果改为 int flag = pthread_mutex_lock(&mut);
* 则为阻塞的,该线程会被加入队列等待开锁
********************************************/
/**************************************************
* 非阻塞如果不为零说明有其他线程正在进行,即不应该执行该线程
* 因此可以判断flag并退出该线程
**************************************************/
int *id = (int*)i;
int flag = pthread_mutex_trylock(&mut);
if (flag==0)
{
sleep(1);
for (int j=0;j<5;j++)
printf("thread %d: %d\n", *id, j);
pthread_mutex_unlock(&mut);
}
else
{
printf("thread %d: 其他线程正在进行\n", *id);
}
}
int main()
{
pthread_t td[5]; // 初始化线程
for(int i=0;i<5;i++)
tf[i] = i;
for(int i=0;i<5;i++)
// 创建线程
pthread_create(&td[i],NULL,print,(void *)&tf[i]);
for(int i=0;i<5;i++)
{
// 运行线程,join函数确保子线程执行完了主程序才退出
pthread_join(td[i],NULL);
}
pthread_mutex_destroy(&mut);
}
条件锁
条件锁就是所谓的条件变量,某一个线程因为某个条件为满足时可以使用条件变量使改程序处于阻塞状态。一旦条件满足以“信号量”的方式唤醒一个因为该条件而被阻塞的线程。
头文件:<pthread.h>
类型:pthread_cond_t
- pthread_cond_wait:线程阻塞在条件变量
- pthread_cond_signal:线程被唤醒
linux C++ 多线程使用pthread_cond 条件变量
线程属性pthread_attr_t简介
例程
- 线程0、线程1互斥加一个数,加一次唤醒一次条件触发的线程2,如果线程2处于阻塞等待状态则被唤醒
- 线程2判断数值大小时,给线程0、1上锁,停止加数,当数字小于10时,等待3秒,否则加100退出该线程
- 线程0、1各加10次退出线程,线程2检测到数字大于10加100后退出线程,三个线程都结束程序退出
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#define NUM_THREADS 3
#define TCOUNT 10
#define COUNT_LIMIT 10
int count = 0;
int thread_ids[3] = {0,1,2};
pthread_mutex_t count_mutex; // 计数时上锁
pthread_cond_t count_threshold_cv;
void *inc_count(void *idp)
{
int i = 0;
int taskid = 0;
int *my_id = (int*)idp;
for (i=0; i<TCOUNT; i++) {
// 互斥锁上锁
pthread_mutex_lock(&count_mutex);
taskid = count;
count++;
/*
唤醒一个阻塞在该条件变量的线程
如果没有线程被阻塞在条件变量上,那么调用pthread_cond_signal()将没有作用
*/
pthread_cond_signal(&count_threshold_cv);
printf("inc_count(): thread %d, count = %d, 开互斥锁\n", *my_id, count);
// 互斥锁解锁
pthread_mutex_unlock(&count_mutex);
sleep(1);
}
printf("inc_count(): thread %d, Threshold reached.\n", *my_id);
pthread_exit(NULL);
}
void *watch_count(void *idp)
{
int *my_id = (int*)idp;
printf("Starting watch_count(): thread %d\n", *my_id);
pthread_mutex_lock(&count_mutex);
while(count<COUNT_LIMIT) {
sleep(3);
/*
函数将自动/原子到解锁mutex参数指向的互斥锁,
并使当前线程阻塞在cv参数指向的条件变量上
被阻塞的线程可以被pthread_cond_signal函数,
pthread_cond_broadcast函数唤醒,
也可能在被信号中断后被唤醒
pthread_cond_wait函数的返回并不意味着条件的值一定发生了变化,
必须重新检查条件的值.
本例子中使用类COUNT_LIMIT最为满足条件的值
pthread_cond_wait函数返回时,相应的互斥锁将被当前线程锁定,
即使是函数出错返回
*/
pthread_cond_wait(&count_threshold_cv, &count_mutex);
printf("watch_count(): thread %d 收到条件信号.\n", *my_id);
}
count += 100;
pthread_mutex_unlock(&count_mutex);
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
int i, rc;
pthread_t threads[3];
pthread_attr_t attr; // 线程属性
/* Initialize mutex and condition variable objects */
pthread_mutex_init(&count_mutex, NULL);
pthread_cond_init (&count_threshold_cv, NULL);
/* For portability, explicitly create threads in a joinable state */
pthread_attr_init(&attr); // 对线程属性变量的初始化
/*
设置线程detachstate属性。该表示新线程是否与进程中其他线程脱离同步,
如果设置为PTHREAD_CREATE_DETACHED则新线程不能用pthread_join()来同步,
且在退出时自行释放所占用的资源。缺省为PTHREAD_CREATE_JOINABLE状态。
这个属性也可以在线程创建并运行以后用pthread_detach()来设置,
而一旦设置为PTHREAD_CREATE_DETACH状态(不论是创建时设置还是运行时设置)
则不能再恢复到PTHREAD_CREATE_JOINABLE状态。
*/
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&threads[0], &attr, inc_count, (void *)&thread_ids[0]);
pthread_create(&threads[1], &attr, inc_count, (void *)&thread_ids[1]);
pthread_create(&threads[2], &attr, watch_count, (void *)&thread_ids[2]);
/* Wait for all threads to complete */
for (i=0; i<NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
printf ("Main(): Waited on %d threads. Done.\n", NUM_THREADS);
/* Clean up and exit */
pthread_attr_destroy(&attr);
pthread_mutex_destroy(&count_mutex);
pthread_cond_destroy(&count_threshold_cv);
pthread_exit(NULL);
return 0;
}
自旋锁
当发生阻塞时,互斥锁可以让CPU去处理其他的任务;而自旋锁让CPU一直不断循环请求获取这个锁,它会一直占用CPU请求这个自旋锁使得CPU不能去做其他的事情,直到获取这个锁为止,比较耗费CPU
头文件:<pthread.h>
类型:pthread_spinlock_t
- 初始化:pthread_spin_init(pthread_spinlock_t *__lock, int __pshared);
- pthread_spin_lock(x); //只有在获得锁的情况下才返回,否则一直“自旋”
- pthread_spin_trylock(x); //如果该锁已经被争用,那么该函数立即返回一个非0值,而不会自旋等待锁被释放;
- 释放锁:phtread_spin_unlock(x);
- 释放资源:pthread_spin_destroy(&lock);
注意:自旋锁适合于短时间的的轻量级的加锁机制
代码同互斥锁,更改init、lock、unlock、destroy即可