-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <pthread.h>
-
-
int main(){
-
pthread_t thread_id;
-
-
thread_id=pthread_self(); // 返回调用线程的线程ID
-
printf("Thread ID: %lu.\n",thread_id);
-
-
if (pthread_equal(thread_id,pthread_self())) {
-
// if (thread_id==0) {
-
printf("Equal!\n");
-
} else {
-
printf("Not equal!\n");
-
}
-
return 0;
-
}
线程编程
操作用户空间中的线程
创建线程
?调用该线程函数的入口点
?使用函数pthread_create(),线程创建后,就开始运行相关的线程函数
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <pthread.h>
-
-
void *thrd_func(void *arg);
-
pthread_t tid;
-
-
int main(){
-
// 创建线程tid,且线程函数由thrd_func指向,是thrd_func的入口点,即马上执行此线程函数
-
if (pthread_create(&tid,NULL,thrd_func,NULL)!=0) {
-
printf("Create thread error!\n");
-
exit(1);
-
}
-
-
printf("TID in pthread_create function: %u.\n",tid);
-
printf("Main process: PID: %d,TID: %u.\n",getpid(),pthread_self());
-
-
sleep(1); //race
-
-
return 0;
-
}
-
-
void *thrd_func(void *arg){
-
// printf("I am new thread!\n");
-
printf("New process: PID: %d,TID: %u.\n",getpid(),pthread_self()); //why pthread_self
-
printf("New process: PID: %d,TID: %u.\n",getpid(),tid); //why pthread_self
-
-
pthread_exit(NULL); //退出线程
-
// return ((void *)0);
-
}
退出线程
?在线程函数运行完后,该线程也就退出了
?或使用函数pthread_exit(),这是线程的主动行为
?不能使用exit()
使调用进程终止,所有线程都终止了
等待线程
?由于一个进程中的多个线程是共享数据段的,通常在线程退出之后,退出线程所占用的资源并不会随着线程的终止而得到释放
?pthread_join()函数
类似进程的wait()/waitpid()函数,用于将当前线程挂起来等待线程的结束
是一个线程阻塞的函数,调用它的线程一直等待到被等待的线程结束为止
函数返回时,被等待线程的资源就被收回
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <pthread.h>
-
-
void *thrd_func1(void *arg);
-
void *thrd_func2(void *arg);
-
-
int main(){
-
pthread_t tid1,tid2;
-
void *tret;
-
// 创建线程tid1,线程函数thrd_func1
-
if (pthread_create(&tid1,NULL,thrd_func1,NULL)!=0) {
-
printf("Create thread 1 error!\n");
-
exit(1);
-
}
-
// 创建线程tid2,线程函数thrd_func2
-
if (pthread_create(&tid2,NULL,thrd_func2,NULL)!=0) {
-
printf("Create thread 2 error!\n");
-
exit(1);
-
}
-
// 等待线程tid1结束,线程函数返回值放在tret中
-
if (pthread_join(tid1,&tret)!=0){
-
printf("Join thread 1 error!\n");
-
exit(1);
-
}
-
-
printf("Thread 1 exit code: %d.\n",(int *)tret);
-
// 等待tid2结束,线程函数返回值放在tret中
-
if (pthread_join(tid2,&tret)!=0){
-
printf("Join thread 2 error!\n");
-
exit(1);
-
}
-
-
printf("Thread 2 exit code: %d.\n",(int *)tret);
-
-
return 0;
-
}
-
-
void *thrd_func1(void *arg){
-
printf("Thread 1 returning!\n");
-
// sleep(3);
-
return ((void *)1); // 自动退出线程
-
}
-
-
void *thrd_func2(void *arg){
-
printf("Thread 2 exiting!\n");
-
pthread_exit((void *)2); // 线程主动退出,返回(void *)2
-
}
取消线程
?在别的线程中要终止另一个线程
?pthread_cancel()函数
?被取消的线程可以设置自己的取消状态
–被取消的线程接收到另一个线程的取消请求之后,是接受还是忽略这个请求
–如果接受,是立刻进行终止操作还是等待某个函数的调用等
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <pthread.h>
-
-
void *thrd_func1(void *arg);
-
void *thrd_func2(void *arg);
-
-
pthread_t tid1,tid2;
-
-
int main(){
-
// 创建线程tid1,线程函数thrd_func1
-
if (pthread_create(&tid1,NULL,thrd_func1,NULL)!=0) {
-
printf("Create thread 1 error!\n");
-
exit(1);
-
}
-
// 创建线程tid2,线程函数thrd_func2
-
if (pthread_create(&tid2,NULL,thrd_func2,NULL)!=0) {
-
printf("Create thread 2 error!\n");
-
exit(1);
-
}
-
// 等待线程tid1退出
-
if (pthread_join(tid1,NULL)!=0){
-
printf("Join thread 1 error!\n");
-
exit(1);
-
}else
-
printf("Thread 1 Joined!\n");
-
// 等待线程tid2退出
-
if (pthread_join(tid2,NULL)!=0){
-
printf("Join thread 2 error!\n");
-
exit(1);
-
}else
-
printf("Thread 2 Joined!\n");
-
-
return 0;
-
}
-
-
void *thrd_func1(void *arg){
-
// pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
-
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); // 设置其他线程可以cancel掉此线程
-
-
while(1) {
-
printf("Thread 1 is running!\n");
-
sleep(1);
-
}
-
pthread_exit((void *)0);
-
}
-
-
void *thrd_func2(void *arg){
-
printf("Thread 2 is running!\n");
-
sleep(5);
-
if (pthread_cancel(tid1)==0) // 线程tid2向线程tid1发送cancel
-
printf("Send Cancel cmd to Thread 1.\n");
-
-
pthread_exit((void *)0);
-
}
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <pthread.h>
-
-
#define THREAD_NUM 3
-
#define REPEAT_TIMES 5
-
#define DELAY 4
-
-
void *thrd_func(void *arg);
-
-
int main(){
-
pthread_t thread[THREAD_NUM];
-
int no;
-
void *tret;
-
-
srand((int)time(0)); // 初始化随机函数发生器
-
-
for(no=0;no<THREAD_NUM;no++){
-
if (pthread_create(&thread[no],NULL,thrd_func,(void*)no)!=0) { // 创建THREAD_NUM个线程,传入(void*)no作为thrd_func的参数
-
printf("Create thread %d error!\n",no);
-
exit(1);
-
} else
-
printf("Create thread %d success!\n",no);
-
}
-
-
for(no=0;no<THREAD_NUM;no++){
-
if (pthread_join(thread[no],&tret)!=0){ // 等待thread[no]线程结束,线程函数返回值放在tret中
-
printf("Join thread %d error!\n",no);
-
exit(1);
-
}else
-
printf("Join thread %d success!\n",no);
-
}
-
-
return 0;
-
}
-
-
void *thrd_func(void *arg){
-
int thrd_num=(void*)arg;
-
int delay_time=0;
-
int count=0;
-
-
printf("Thread %d is starting.\n",thrd_num);
-
for(count=0;count<REPEAT_TIMES;count++) {
-
delay_time=(int)(DELAY*(rand()/(double)RAND_MAX))+1;
-
sleep(delay_time);
-
printf("\tThread %d:job %d delay =%d.\n",thrd_num,count,delay_time);
-
}
-
-
printf("Thread %d is exiting.\n",thrd_num);
-
pthread_exit(NULL);
-
}
线程同步与互斥
线程共享进程的资源和地址空间,对这些资源进行操作时,必须考虑线程间同步与互斥问题
三种线程同步机制
?互斥锁
?信号量
?条件变量
互斥锁更适合同时可用的资源是惟一的情况
信号量更适合同时可用的资源为多个的情况
互斥锁
用简单的加锁方法控制对共享资源的原子操作
只有两种状态: 上锁、解锁
可把互斥锁看作某种意义上的全局变量
在同一时刻只能有一个线程掌握某个互斥锁,拥有上锁状态的线程能够对共享资源进行操作
若其他线程希望上锁一个已经被上锁的互斥锁,则该线程就会挂起,直到上锁的线程释放掉互斥锁为止
互斥锁保证让每个线程对共享资源按顺序进行原子操作
互斥锁分类
区别在于其他未占有互斥锁的线程在希望得到互斥锁时是否需要阻塞等待
快速互斥锁
?调用线程会阻塞直至拥有互斥锁的线程解锁为止
?默认为快速互斥锁
检错互斥锁
?为快速互斥锁的非阻塞版本,它会立即返回并返回一个错误信息
互斥锁主要包括下面的基本函数:
互斥锁初始化:pthread_mutex_init()
互斥锁上锁:pthread_mutex_lock()
互斥锁判断上锁:pthread_mutex_trylock()
互斥锁解锁:pthread_mutex_unlock()
消除互斥锁:pthread_mutex_destroy()
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <pthread.h>
-
-
#define THREAD_NUM 3
-
#define REPEAT_TIMES 5
-
#define DELAY 4
-
-
pthread_mutex_t mutex;
-
-
void *thrd_func(void *arg);
-
-
int main(){
-
pthread_t thread[THREAD_NUM];
-
int no;
-
void *tret;
-
-
srand((int)time(0));
-
// 创建快速互斥锁(默认),锁的编号返回给mutex
-
pthread_mutex_init(&mutex,NULL);
-
-
// 创建THREAD_NUM个线程,每个线程号返回给&thread[no],每个线程的入口函数均为thrd_func,参数为
-
for(no=0;no<THREAD_NUM;no++){
-
if (pthread_create(&thread[no],NULL,thrd_func,(void*)no)!=0) {
-
printf("Create thread %d error!\n",no);
-
exit(1);
-
} else
-
printf("Create thread %d success!\n",no);
-
}
-
-
// 对每个线程进行join,返回值给tret
-
for(no=0;no<THREAD_NUM;no++){
-
if (pthread_join(thread[no],&tret)!=0){
-
printf("Join thread %d error!\n",no);
-
exit(1);
-
}else
-
printf("Join thread %d success!\n",no);
-
}
-
// 消除互斥锁
-
pthread_mutex_destroy(&mutex);
-
return 0;
-
}
-
-
void *thrd_func(void *arg){
-
int thrd_num=(void*)arg; // 传入的参数,互斥锁的编号
-
int delay_time,count;
-
-
// 对互斥锁上锁
-
if(pthread_mutex_lock(&mutex)!=0) {
-
printf("Thread %d lock failed!\n",thrd_num);
-
pthread_exit(NULL);
-
}
-
-
printf("Thread %d is starting.\n",thrd_num);
-
for(count=0;count<REPEAT_TIMES;count++) {
-
delay_time=(int)(DELAY*(rand()/(double)RAND_MAX))+1;
-
sleep(delay_time);
-
printf("\tThread %d:job %d delay =%d.\n",thrd_num,count,delay_time);
-
}
-
-
printf("Thread %d is exiting.\n",thrd_num);
-
// 解锁
-
pthread_mutex_unlock(&mutex);
-
-
pthread_exit(NULL);
-
}
和上一版本的程序差异在于有没有锁,有锁的情况下,必须等"thread x is exiting."之后其他线程才能继续。
信号量
操作系统中所用到的PV原子操作,广泛用于进程或线程间的同步与互斥
?本质上是一个非负的整数计数器,被用来控制对公共资源的访问
PV原子操作:对整数计数器信号量sem的操作
?一次P操作使sem减一,而一次V操作使sem加一
?进程(或线程)根据信号量的值来判断是否对公共资源具有访问权限
–当信号量sem的值大于等于零时,该进程(或线程)具有公共资源的访问权限
–当信号量sem的值小于零时,该进程(或线程)就将阻塞直到信号量sem的值大于等于0为止
PV操作主要用于线程间的同步和互斥
互斥,几个线程只设置一个信号量sem
同步,会设置多个信号量,安排不同初值来实现它们之间的顺序执行
信号量函数
sem_init() 创建一个信号量,并初始化它
sem_wait()和sem_trywait(): P操作,在信号量大于零时将信号量的值减一
?区别: 若信号量小于零时,sem_wait()将会阻塞线程,sem_trywait()则会立即返回
sem_post(): V操作,将信号量的值加一同时发出信号来唤醒等待的线程
sem_getvalue(): 得到信号量的值
sem_destroy(): 删除信号量
eg. 同步各线程,执行顺序为逆序。
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <pthread.h>
-
#include <semaphore.h>
-
-
#define THREAD_NUM 3
-
#define REPEAT_TIMES 5
-
#define DELAY 4
-
-
sem_t sem[THREAD_NUM];
-
-
void *thrd_func(void *arg);
-
-
int main(){
-
pthread_t thread[THREAD_NUM];
-
int no;
-
void *tret;
-
-
srand((int)time(0));
-
-
// 初始化THREAD_NUM-1个信号量,均初始化为0
-
for(no=0;no<THREAD_NUM-1;no++){
-
sem_init(&sem[no],0,0);
-
}
-
-
// sem[2]信号量初始化为1,即sem数组中最后一个信号量
-
sem_init(&sem[2],0,1);
-
-
// 创建THREAD_NUM个线程,入口函数均为thrd_func,参数为(void*)no
-
for(no=0;no<THREAD_NUM;no++){
-
if (pthread_create(&thread[no],NULL,thrd_func,(void*)no)!=0) {
-
printf("Create thread %d error!\n",no);
-
exit(1);
-
} else
-
printf("Create thread %d success!\n",no);
-
}
-
-
// 逐个join掉THREAD_NUM个线程
-
for(no=0;no<THREAD_NUM;no++){
-
if (pthread_join(thread[no],&tret)!=0){
-
printf("Join thread %d error!\n",no);
-
exit(1);
-
}else
-
printf("Join thread %d success!\n",no);
-
}
-
-
// 逐个取消信号量
-
for(no=0;no<THREAD_NUM;no++){
-
sem_destroy(&sem[no]);
-
}
-
-
return 0;
-
}
-
-
void *thrd_func(void *arg){
-
int thrd_num=(void*)arg; // 参数no
-
int delay_time,count;
-
-
// 带有阻塞的p操作
-
sem_wait(&sem[thrd_num]);
-
-
-
printf("Thread %d is starting.\n",thrd_num);
-
for(count=0;count<REPEAT_TIMES;count++) {
-
delay_time=(int)(DELAY*(rand()/(double)RAND_MAX))+1;
-
sleep(delay_time);
-
printf("\tThread %d:job %d delay =%d.\n",thrd_num,count,delay_time);
-
}
-
-
printf("Thread %d is exiting.\n",thrd_num);
-
-
// 对前一个信号量进行V操作
-
// 由于只有最后一个信号量初始化为1,其余均为0
-
// 故线程执行的顺序将为逆序
-
sem_post(&sem[(thrd_num+THREAD_NUM-1)%THREAD_NUM]);
-
-
pthread_exit(NULL); // 线程主动结束
-
}
个人总结:线程的编程需要考虑用,锁机制,条件变量或者信号量,当信号量的值只是0,1的时候,就直接可以当做锁来用。条件变量的使用需要和锁机制来进行搭配使用。
转载地址:http://www.cnblogs.com/forstudy/archive/2012/04/05/2433853.html