配置VS2013 使用pthread,参考:
http://blog.csdn.net/k459905889/article/details/48676159pthread函数使用,参考:
http://blog.csdn.net/dreamintheworld/article/details/52577681
线程状态及结束资源回收:
http://blog.163.com/sunjinxia@126/blog/static/949848792013214386222/
线程创建的时候默认处于joinable状态,此状态线程结束的时候不会自动回收线程资源,需要pthread_join函数来回收;pthread_detach可以讲线程转换为detached状态,子线程运行完成之后可以自行回收资源。
多线程
线程创建:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
using namespace::std;
#define THREAD_NUMBER 3//线程数
#define REPEAT_NUMBER 5//每个线程中小任务数
#define DELAY_TIME_LEVELS 10.0//小任务之间的最大时间间隔
#pragma comment(lib,"pthreadVC2.lib")
//线程函数
void * thrd_func(void * arg)
{
int thrd_num = (int)arg;
int delay_time = 0;
int count = 0;
printf("线程%d 开始\n", thrd_num);
for (count = 0; count < REPEAT_NUMBER;count++)
{
delay_time = (int)(rand()*DELAY_TIME_LEVELS / (RAND_MAX)+1);
Sleep(delay_time);
printf("\t线程%d:job %d delay = %d\n", thrd_num, count, delay_time);
}
printf("线程%d 完成\n",thrd_num);
pthread_exit(NULL);
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t thread[THREAD_NUMBER];//线程的标识符
int i = 0, res;
srand(time(NULL));
//创建线程
for (i = 0; i < THREAD_NUMBER;++i)
{
res = pthread_create(&thread[i], NULL, thrd_func, (void*)i);
if (res)
{
printf("线程%d创建失败!\n", i);
exit(res);
}
}
printf("线程全部创建完成!\n等待线程结束、、、\n");
//等待线程结束
void* thrd_ret;
for (i = 0; i < THREAD_NUMBER;++i)
{
res = pthread_join(thread[i], &thrd_ret);//阻塞等待结束
if (!res)
{
printf("线程%djoined\n", i);
}
else
{
printf("线程%djoined 失败!\n");
}
}
return 0;
}
互斥锁使用:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
using namespace::std;
#define THREAD_NUMBER 3//线程数
#define REPEAT_NUMBER 5//每个线程中小任务数
#define DELAY_TIME_LEVELS 10.0//小任务之间的最大时间间隔
#pragma comment(lib,"pthreadVC2.lib")
pthread_mutex_t mutex;//互斥锁
//线程函数
void * thrd_func(void * arg)
{
int thrd_num = (int)arg;
int delay_time = 0, count = 0;
int res;
res = pthread_mutex_lock( &mutex );
if (res)
{
printf("线程%d 上锁失败\n", thrd_num);
pthread_exit(NULL);
}
printf("线程%d 开始\n", thrd_num);
for (count = 0; count < REPEAT_NUMBER;count++)
{
delay_time = (int)(rand()*DELAY_TIME_LEVELS / (RAND_MAX)+1);
Sleep(delay_time);
printf("\t线程%d:job %d delay = %d\n", thrd_num, count, delay_time);
}
printf("线程%d 完成\n",thrd_num);
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t thread[THREAD_NUMBER];//线程的标识符
int i = 0, res;
srand(time(NULL));
//互斥锁初始化
pthread_mutex_init(&mutex, NULL);
//创建线程
for (i = 0; i < THREAD_NUMBER;++i)
{
res = pthread_create(&thread[i], NULL, thrd_func, (void*)i);
if (res)
{
printf("线程%d创建失败!\n", i);
exit(res);
}
}
printf("线程全部创建完成!\n等待线程结束、、、\n");
//等待线程结束
void* thrd_ret;
for (i = 0; i < THREAD_NUMBER;++i)
{
res = pthread_join(thread[i], &thrd_ret);//阻塞等待结束
if (!res)
{
printf("线程%djoined\n", i);
}
else
{
printf("线程%djoined 失败!\n");
}
}
pthread_mutex_destroy(&mutex);
return 0;
}
调用pthread_mutex_lock上锁,发现上锁时候后进入等待,等待锁再次释放后重新上锁;
所以线程程序加载到队列中等待,等待成功上锁后继续执行程序代码;
自旋锁使用:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <semaphore.h>
#include <iostream>
using namespace::std;
#define THREAD_NUMBER 3//线程数
#pragma comment(lib,"pthreadVC2.lib")
pthread_spinlock_t spinlock;
void* thred_func(void* thrd_id)
{
int id = (int)thrd_id;
pthread_spin_lock(&spinlock);
cout <<"线程"<< id <<"执行!"<<endl;
pthread_spin_unlock(&spinlock);
pthread_exit(NULL);
return NULL;
}
int main()
{
pthread_t thread[THREAD_NUMBER];
pthread_spin_init(&spinlock, 0);
int res;
for (auto i = 0; i < THREAD_NUMBER;++i)
{
res = pthread_create(&thread[i], NULL, thred_func, (void*)i);
if (res)
{
cout << "线程"<<i<<"创建失败!" << endl;
exit(res);
}
}
void * thrd_ret;
for (auto i = 0; i < THREAD_NUMBER;++i)
{
res = pthread_join(thread[i], &thrd_ret);
if (!res)
{
cout << "线程" << i << "joined" << endl;
}
else
{
cout << "线程" << i << "joined 失败" << endl;
}
}
pthread_spin_destroy(&spinlock);
return 0 ;
}
信号量使用:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <semaphore.h>
using namespace::std;
#define THREAD_NUMBER 3//线程数
#define REPEAT_NUMBER 5//每个线程中小任务数
#define DELAY_TIME_LEVELS 10.0//小任务之间的最大时间间隔
#pragma comment(lib,"pthreadVC2.lib")
sem_t sem[THREAD_NUMBER];//信号量
//线程函数
void * thrd_func(void * arg)
{
int thrd_num = (int)arg;
int delay_time = 0, count = 0;
int res;
sem_wait(&sem[thrd_num]);
printf("线程%d 开始\n", thrd_num);
for (count = 0; count < REPEAT_NUMBER;count++)
{
delay_time = (int)(rand()*DELAY_TIME_LEVELS / (RAND_MAX)+1);
Sleep(delay_time);
printf("\t线程%d:job %d delay = %d\n", thrd_num, count, delay_time);
}
printf("线程%d 完成\n",thrd_num);
sem_post(&sem[thrd_num-1]);
pthread_exit(NULL);
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t thread[THREAD_NUMBER];//线程的标识符
int i = 0, res;
srand(time(NULL));
//信号量初始化
for (i = 0; i < THREAD_NUMBER;++i)
{
sem_init(&sem[i], 0, 0);//信号量指针,共享级别:0:线程/else:进程,初始值
}
//创建线程
for (i = 0; i < THREAD_NUMBER;++i)
{
res = pthread_create(&thread[i], NULL, thrd_func, (void*)i);
if (res)
{
printf("线程%d创建失败!\n", i);
exit(res);
}
}
printf("线程全部创建完成!\n等待线程结束、、、\n");
sem_post(&sem[THREAD_NUMBER - 1]);
//等待线程结束
void* thrd_ret;
for (i = 0; i < THREAD_NUMBER;++i)
{
res = pthread_join(thread[THREAD_NUMBER-1-i], &thrd_ret);//阻塞等待结束
if (!res)
{
printf("线程%djoined\n", i);
}
else
{
printf("线程%djoined 失败!\n");
}
}
for (i = 0; i < THREAD_NUMBER;++i)
{
sem_destroy(&sem[i]);
}
return 0;
}
条件变量使用:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <semaphore.h>
#include <iostream>
using namespace::std;
#define THREAD_NUMBER 3//线程数
#pragma comment(lib,"pthreadVC2.lib")
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int i = 1;
//线程函数1
void * thread1(void*)
{
Sleep(1);//必须保证线程2在线程1之前运行到pthread_cond_wait
pthread_mutex_lock(&mutex);
cout << "线程1 开始" << endl;
pthread_cond_signal(&cond);
cout << "线程1 结束" << endl;
pthread_mutex_unlock(&mutex);
return NULL;
}
void *thread2(void *junk)
{
pthread_mutex_lock(&mutex);
cout << "线程2 开始" << endl;
pthread_cond_wait(&cond, &mutex);/*解锁mutex,并等待cond改变*/
cout << "线程2 重启" << endl;
cout << "线程2 结束" << endl;
pthread_mutex_unlock(&mutex);
return NULL;
}
int main()
{
pthread_t t_a;
pthread_t t_b;
pthread_create(&t_a, NULL, thread1, (void*)NULL);
pthread_create(&t_b, NULL, thread2, (void*)NULL);
pthread_join(t_a, NULL);
pthread_join(t_b, NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}
pthread_cond_wait会先解除之前的pthread_mutex_lock锁定的mutex,然后阻塞在等待对列里休眠,直到再次被唤醒(大多数情况下是等待的条件成立而被唤醒,唤醒后,该进程会先锁定先pthread_mutex_lock(&mutex);,再读取资源。
用这个流程是比较清楚的: block–>unlock–>wait() return–>lock
pthread_cond_broadcast()与pthread_cond_signal()有什么区别?
signal 是唤醒N多 race 中的一个,具体那个被唤醒,依赖于操作系统。
broadcast 是唤醒N多reace 的全部。
注:broadcast后的非空检查:把资源放入时候后signal或者broadcast,这个时候如果是broadcast,那么可能会唤起很多线程对mutex进行锁竞争,但是必须注意一点,竞争到锁后,对拿到的资源需要进行非空检查,因为别的线程可能已经拿到锁,然后处理完资源把资源清空了。
读写锁使用
参考:http://blog.csdn.net/lovecodeless/article/details/24968369
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <semaphore.h>
#include <iostream>
#pragma comment(lib,"pthreadVC2.lib")
using namespace::std;
pthread_rwlock_t rwlock;
pthread_t readerM, readerN, writerA, writerB;
int data(1);//共享资源
void* readM(void * arg)
{
while (1)
{
pthread_rwlock_rdlock(&rwlock);
cout << "读者M 读取数据:" << data << endl;
pthread_rwlock_unlock(&rwlock);
Sleep(1200);
}
return NULL;
}
void* readN(void * arg)
{
while (1)
{
pthread_rwlock_rdlock(&rwlock);
cout << "读者N 读取数据:" << data << endl;
pthread_rwlock_unlock(&rwlock);
Sleep(1200);
}
return NULL;
}
void* writeA(void * arg)
{
while (1)
{
pthread_rwlock_wrlock(&rwlock);
data++;
cout << "写者A 写入数据:" << data << endl;
pthread_rwlock_unlock(&rwlock);
Sleep(2000);
}
return NULL;
}
void* writeB(void * arg)
{
while (1)
{
pthread_rwlock_wrlock(&rwlock);
data++;
cout << "写者B 写入数据:" << data << endl;
pthread_rwlock_unlock(&rwlock);
Sleep(2000);
}
return NULL;
}
int main()
{
pthread_rwlock_init(&rwlock,NULL);
pthread_create(&readerM, NULL, readM, NULL);
pthread_create(&readerN, NULL, readN, NULL);
pthread_create(&writerA, NULL, writeA, NULL);
pthread_create(&writerB, NULL, writeB, NULL);
void * res;
pthread_join(readerM,&res);
pthread_join(readerN,&res);
pthread_join(writerA,&res);
pthread_join(writerB,&res);
pthread_rwlock_destroy(&rwlock);
return 0;
}
例题:3个线程,线程id是1,2,3 打印 1、2、3、1、2、3、、
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <semaphore.h>
#include <iostream>
using namespace::std;
#define THREAD_NUMBER 3//线程数
#define REPEAT_NUMBER 5//每个线程中小任务数
#define DELAY_TIME_LEVELS 10.0//小任务之间的最大时间间隔
#pragma comment(lib,"pthreadVC2.lib")
sem_t sem[THREAD_NUMBER];
void* thred_func(void* thrd_id)
{
int id = (int)thrd_id;
while (1)
{
sem_wait(&sem[id]);
cout << id+1 << "、";
sem_post(&sem[(id+1)%THREAD_NUMBER]);
}
pthread_exit(NULL);
return NULL;
}
int main()
{
pthread_t thread[THREAD_NUMBER];
for (auto i = 0; i < THREAD_NUMBER;++i)
{
sem_init(&sem[i], 0, 0);
}
int res;
for (auto i = 0; i < THREAD_NUMBER;++i)
{
res = pthread_create(&thread[i], NULL, thred_func, (void*)i);
if (res)
{
cout << "线程"<<i<<"创建失败!" << endl;
exit(res);
}
}
sem_post(&sem[0]);
void * thrd_ret;
for (auto i = 0; i < THREAD_NUMBER;++i)
{
res = pthread_join(thread[i], &thrd_ret);
if (!res)
{
cout << "线程" << i << "joined" << endl;
}
else
{
cout << "线程" << i << "joined 失败" << endl;
}
}
for (auto i = 0; i < THREAD_NUMBER;++i)
{
sem_destroy(&sem[i]);
}
return 0 ;
}
用户级线程、内核级线:
线程按照其调度者可以分为用户级线程和内核级线程两种。
- 用户级线程:
我们常用基本就是用户级线程,有关线程管理的工作由应用程序完成,用户级线程主要解决的是上下文切换的问题,它的调度算法和调度过程全部由用户自行选择决定,在运行时内核意识不到线程的存在。
用户级线程优点:
1. 不需要内核态与用户态切换
2. 可在任意操作系统运行用户级线程缺点:
1. 一个线程阻塞则所有线程阻塞。
2. 纯粹用户级线程策略中,无法利用多核处理技术,内核一次只把一个进程分配给一个处理器,一个进程中只有一个线程可以执行。
- 内核级线程:
有关线程管理的工作由内核完成,应用程序没有线程管理代码,只有一个内核提供的应用程序API
内核级线程优点:
1. 内核可将一个进程中的多个线程调度到多个处理器中,内核本身也可以多处理运行。
2. 一个线程阻塞,内核可以调用一个进程中的另一个线程内核级线程缺点:
1. 线程切换需要到内核的状态切换
多线程使用了多核吗?
SMP:对称多处理系统,内核可以在任何处理器上执行。
- windows:
windows使用两类与进程相关的对象:进程和线程。
windows支持SMP硬件配置:任何进程的线程,都可以在任何处理器上运行。同一进程中的多个线程可以在多个处理器上同时执行。
- Linux
Linux提供一种不区分进程和线程的方案,用户级线程被映射到内核级进程上,组成一个用户级进程的多个用户级线程被映射到共享同一组ID的多个linux内核级进程上。
Linux中线程和进程没有区别:Linux中通过复制当前的进程的属性可创建一个新进程,新进程被克隆出来,以使它可以共享资源,当两个进程共享虚拟内存时,他们可以被当做是一个进程中的线程。但是没有为线程单独定义数据结构。
linux内核编译时,CONFIG_SMP配置项控制内核是否支持SMP.
现在的内核包从2.4.23以后就没有专门的SMP内核包,在安装Linux系统时,会自动监测,如果检查到了多个CPU或多核,超线程时,会自动安装两个Linux内核,其中一个是带SMP的,在GRUB引导列表里会出现两个内核选择,默认使用SMP引导.
threadlocal,各种锁,synchronized和lock ,
多线程中的wait和sleep区别,notify的作用 ,
线程池对线程的管理方式,包括初始化线程的方法、线程创建后的管理、指派任务的方式
线程池优点、调度处理方式和保护任务队列的方式
无锁编程:
有锁编程的问题与解决方法:阻塞(效率下降)、死锁、优先级反转问题
无锁编程解决单生产者多消费者问题和多生产者多消费者问题
线程安全的接口