
线程概述线程创建一般情况下main函数所在的线程我们称之为主线程其余创建的线程称之为子线程程序中默认只有一个进程fork()函数调用2个进程程序中默认只有一个线程pthread_create()函数调用2个线程#include pthread.hint pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);功能创建一个子线程参数- thread传出参数线程创建成功后子线程的线程ID被写到该变量中- attr设置线程的属性一般使用默认值NULL- start_routine函数指针这个函数是子线程需要处理的逻辑代码- arg给第三个参数使用传参返回值成功0失败返回错误号这个错误号和之前errno不太一样获取错误号信息char *strerror(int errnum); //#include string.h#include stdio.h #include pthread.h #include string.h #include unistd.h void *callback(void *arg) { printf(child thread...\n); printf(arg value :%d\n,*(int *)arg); return NULL; } int main() { pthread_t tid; int num 10; //创建一个子线程 int ret pthread_create(tid,NULL,callback,(void*)num); if(ret ! 0) { char *errstr strerror(ret); printf(error : %s\n,errstr); } for(int i 0;i 5;i ) { printf(%d\n,i); } sleep(1); return 0; }线程终止#include pthread.hvoid pthread_exit(void *retval);功能终止一个线程在哪个线程中调用就表示终止哪个线程参数reval需要传递一个指针作为一个返回值可以在pthread_join()中pthread_t pthread_self(void);功能获取当前的线程的线程IDint pthread_equal(pthread_t t1,pthread_t t2);功能比较两个线程ID是否相等不同的操作系统pthread_t类型的实现有的是无符号的长整型有的是使用结构体去实现的#include stdio.h #include pthread.h #include string.h void *callback(void *arg) { printf(child thread id:%ld\n,pthread_self()); return NULL; //pthread_exit(NULL) } int main() { //创建一个子线程 pthread_t tid; int ret pthread_create(tid,NULL,callback,NULL); if(ret ! 0) { char *errstr strerror(ret); printf(error:%s\n,errstr); } //主线程 for(int i 0;i 5;i ) { printf(%d\n,i); } printf(tid :%ld ,main thread id:%ld\n,tid,pthread_self()); //让主线程退出 pthread_exit(NULL); return 0; }#include pthread.hint pthread_join(pthread_t thread, void **retval);功能和一个已经终止的线程进行连接回收子线程的资源这个函数是阻塞函数调用一次只能回收一个子线程一般在主线程中使用参数thread需要回收的子线程的IDretval接收子线程退出时的返回值返回值0成功非0失败返回的错误号#include stdio.h #include pthread.h #include string.h #include unistd.h int value 10; void *callback(void *arg) { printf(child thread id:%ld\n,pthread_self()); //sleep(3); pthread_exit((void*)value); } int main() { //创建一个子线程 pthread_t tid; int ret pthread_create(tid,NULL,callback,NULL); if(ret ! 0) { char *errstr strerror(ret); printf(error:%s\n,errstr); } //主线程 for(int i 0;i 5;i ) { printf(%d\n,i); } printf(tid :%ld ,main thread id:%ld\n,tid,pthread_self()); //主线程调用pthread_join()回收子线程的资源 int *thread_retval; ret pthread_join(tid,(void **)thread_retval);//不需要传参则可以写NULL if(ret ! 0) { char *errstr strerror(ret); printf(error:%s\n,errstr); } printf(exit data : %d\n,*thread_retval); printf(回收子线程资源成功\n); //让主线程退出 pthread_exit(NULL); return 0; }线程分离#include pthread.hint pthread_detach(pthread_t thread);功能分离一个线程被分离的线程在终止的时候会自动释放资源返回给系统1、不能多次分离会产生不可预料的行为2、不能用pthread_join()连接一个已经分离的线程操作会报错参数需要分离的线程ID返回值成功0失败返回错误号#include stdio.h #include pthread.h #include string.h #include unistd.h void *callback(void *arg) { printf(child thread id : %ld\n,pthread_self()); return NULL; } int main() { pthread_t tid; int ret pthread_create(tid,NULL,callback,NULL); if(ret ! 0) { char *errstr strerror(ret); printf(error1:%s\n,errstr); } //输出主线程和子线程的id printf(tid : %ld,main thread id:%ld\n,tid,pthread_self()); //设置子线程分离,子线程分离后子线程结束时对应的资源就不需要主线程释放 ret pthread_detach(tid); if(ret ! 0) { char *errstr strerror(ret); printf(error2:%s\n,errstr); } pthread_exit(NULL); return 0; }线程取消#include pthread.hint pthread_cancel(pthread_t thread);功能取消线程让线程终止取消线程可以终止某个线程的运行但是并不是立马终止而是当子线程执行到一个取消点线程才会终止取消点系统规定好的一些系统调用我们可以粗略的理解为从用户区到内核区的切换这个位置称为取消点#include stdio.h #include pthread.h #include string.h #include unistd.h void *callback(void *arg) { printf(child thread id : %ld\n,pthread_self()); for(int i 0;i 5;i ) { printf(child :%d\n,i); } return NULL; } int main() { pthread_t tid; int ret pthread_create(tid,NULL,callback,NULL); if(ret ! 0) { char *errstr strerror(ret); printf(error1:%s\n,errstr); } //输出主线程和子线程的id printf(tid : %ld,main thread id:%ld\n,tid,pthread_self()); //取消线程 pthread_cancel(tid); for(int i 0;i 5;i ) { printf(%d\n,i); } pthread_exit(NULL); return 0; }线程属性int pthread_attr_init(pthread_attr_t *attr);-初始化线程属性变量int pthread_attr_destroy(pthread_attr_t *attr);- 释放线程属性的资源int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);- 获取线程分离的状态属性int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);- 设置线程分离的状态属性#include stdio.h #include pthread.h #include string.h #include unistd.h void *callback(void *arg) { printf(child thread id : %ld\n,pthread_self()); return NULL; } int main() { //创建一个线程属性变量 pthread_attr_t attr; //初始化属性变量 pthread_attr_init(attr); //设置属性 pthread_attr_setdetachstate(attr,PTHREAD_CREATE_DETACHED); pthread_t tid; int ret pthread_create(tid,attr,callback,NULL); if(ret ! 0) { char *errstr strerror(ret); printf(error1:%s\n,errstr); } //输出主线程和子线程的id printf(tid : %ld,main thread id:%ld\n,tid,pthread_self()); //获取线程栈的大小 size_t size; pthread_attr_getstacksize(attr,size); printf(Thread stack size:%ld\n,size); //释放线程属性资源 pthread_attr_destroy(attr); pthread_exit(NULL); return 0; }线程同步互斥量/互斥锁互斥量的类型 pthread_mutex_t◼ int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);- 功能初始化互斥量- 参数-mutex需要初始化的互斥量变量-attr互斥量相关的属性NULL- restrictC语言的修饰符被修饰的指针不能由另外的一个指针进行操作◼ int pthread_mutex_destroy(pthread_mutex_t *mutex);- 功能释放互斥量的资源◼ int pthread_mutex_lock(pthread_mutex_t *mutex);- 功能加锁如果有一个线程加锁那么其他线程只能阻塞等待◼ int pthread_mutex_trylock(pthread_mutex_t *mutex);- 功能尝试加锁如果加锁失败不会阻塞会直接返回◼ int pthread_mutex_unlock(pthread_mutex_t *mutex);- 功能解锁死锁多线程多锁的情况#include stdio.h #include pthread.h #include unistd.h //创建2个互斥量 pthread_mutex_t mutex1,mutex2; void *worka(void *arg) { pthread_mutex_lock(mutex1); sleep(1); pthread_mutex_lock(mutex2); printf(worka...\n); pthread_mutex_unlock(mutex2); pthread_mutex_unlock(mutex1); return NULL; } void *workb(void *arg) { pthread_mutex_lock(mutex2); sleep(1); pthread_mutex_lock(mutex1); printf(workb...\n); pthread_mutex_unlock(mutex1); pthread_mutex_unlock(mutex2); return NULL; } int main() { //初始化互斥量 pthread_mutex_init(mutex1,NULL); pthread_mutex_init(mutex2,NULL); //创建2个子线程 pthread_t tid1,tid2; pthread_create(tid1,NULL,worka,NULL); pthread_create(tid2,NULL,workb,NULL); //回收子线程资源 pthread_join(tid1,NULL); pthread_join(tid2,NULL); //释放互斥量资源 pthread_mutex_destroy(mutex1); pthread_mutex_destroy(mutex2); return 0; }读写锁◼ 读写锁的类型 pthread_rwlock_t◼ int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);◼ int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);◼ int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);◼ int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);◼ int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);◼ int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);◼ int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);#include stdio.h #include pthread.h #include unistd.h /* 案例8个线程操作同一个全局变量 3个线程不定时写这个全局变量5个线程不定时的读这个全局变量 */ int num 1; pthread_rwlock_t rwlock; void *writeNum(void *arg) { while (1) { pthread_rwlock_wrlock(rwlock); num ; printf(write,tid:%ld,num:%d\n,pthread_self(),num); pthread_rwlock_unlock(rwlock); usleep(100); } return NULL; } void *readNum(void *arg) { while(1) { pthread_rwlock_rdlock(rwlock); printf(read,tid:%ld,num : %d\n,pthread_self(),num); pthread_rwlock_unlock(rwlock); usleep(100); } return NULL; } int main() { pthread_rwlock_init(rwlock,NULL); //创建3个写线程5个读线程 pthread_t wtids[3],rtids[5]; for(int i 0;i 3;i ) { pthread_create(wtids[i],NULL,writeNum,NULL); } for(int i 0;i 5;i ) { pthread_create(rtids[i],NULL,readNum,NULL); } //设置线程分离 for(int i 0;i 3;i ) { pthread_detach(wtids[i]); } for(int i 0;i 5;i ) { pthread_detach(rtids[i]); } pthread_exit(NULL); pthread_rwlock_destroy(rwlock); return 0; }生产者消费者模型条件变量与互斥锁一起用◼ 条件变量的类型 pthread_cond_t◼ int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);功能初始化条件变量◼ int pthread_cond_destroy(pthread_cond_t *cond);功能释放条件变量◼ int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);功能阻塞函数调用该函数线程会阻塞当这个函数调用阻塞的时候会对互斥锁进程解锁当不阻塞的时候继续向下执行会重新加锁◼ int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);功能设置等待多少时间调用这个函数线程会阻塞直到指定时间结束◼ int pthread_cond_signal(pthread_cond_t *cond);功能唤醒一个或者多个等待线程◼ int pthread_cond_broadcast(pthread_cond_t *cond);功能唤醒所有等待的线程/* 生产者消费者模型粗略的版本 */ #include stdio.h #include pthread.h #include stdlib.h #include unistd.h struct Node{ int num; struct Node *next; }; pthread_mutex_t mutex; pthread_cond_t cond; //头结点 struct Node *head NULL; void *producer(void *arg) { //不断创建新的结点添加到链表中 while(1) { pthread_mutex_lock(mutex); struct Node *newNode (struct Node*)malloc(sizeof(struct Node)); newNode-next head; head newNode; newNode-num rand() % 1000; printf(add node,num:%d,tid:%ld\n,newNode-num,pthread_self()); //只要生产一个就通知消费者消费 pthread_cond_signal(cond); pthread_mutex_unlock(mutex); usleep(100); } return NULL; } void *customer(void *arg) { while(1) { pthread_mutex_lock(mutex); //判断是否有数据 if(head ! NULL) { //保存头结点的指针 struct Node *tmp head; head head-next; printf(del node,num : %d,tid :%ld\n,tmp-num,pthread_self()); free(tmp); pthread_mutex_unlock(mutex); usleep(100); } else{ //没有数据需要等待 pthread_cond_wait(cond,mutex); pthread_mutex_unlock(mutex); } } return NULL; } int main() { //创建5个生产者线程和5个消费者线程 pthread_mutex_init(mutex,NULL); pthread_cond_init(cond,NULL); pthread_t ptids[5],ctids[5]; for(int i 0;i 5;i ) { pthread_create(ptids[i],NULL,producer,NULL); pthread_create(ctids[i],NULL,customer,NULL); } for(int i 0;i 5;i ) { pthread_detach(ptids[i]); pthread_detach(ctids[i]); } while(1) { sleep(10); } pthread_mutex_destroy(mutex); pthread_cond_destroy(cond); pthread_exit(NULL); return 0; }信号量#include semaphore.h◼ 信号量的类型 sem_t◼ int sem_init(sem_t *sem, int pshared, unsigned int value);功能初始化信号量参数sem信号量psshared0用在线程间 非0用在进程间value信号量中的值◼ int sem_destroy(sem_t *sem);功能释放资源◼ int sem_wait(sem_t *sem);功能对信号量加锁调用一次对这个信号量的值-1如果值为0就阻塞◼ int sem_trywait(sem_t *sem);功能尝试等待◼ int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);◼ int sem_post(sem_t *sem);功能对信号量解锁调用一次对信号量的值1◼ int sem_getvalue(sem_t *sem, int *sval);/* 生产者消费者模型粗略的版本 */ #include stdio.h #include pthread.h #include stdlib.h #include unistd.h #include semaphore.h struct Node{ int num; struct Node *next; }; pthread_mutex_t mutex; //创建两个信号量 sem_t psem; sem_t csem; //头结点 struct Node *head NULL; void *producer(void *arg) { //不断创建新的结点添加到链表中 while(1) { sem_wait(psem); pthread_mutex_lock(mutex); struct Node *newNode (struct Node*)malloc(sizeof(struct Node)); newNode-next head; head newNode; newNode-num rand() % 1000; printf(add node,num:%d,tid:%ld\n,newNode-num,pthread_self()); pthread_mutex_unlock(mutex); sem_post(csem); usleep(100); } return NULL; } void *customer(void *arg) { while(1) { sem_wait(csem); pthread_mutex_lock(mutex); //判断是否有数据 //保存头结点的指针 struct Node *tmp head; head head-next; printf(del node,num : %d,tid :%ld\n,tmp-num,pthread_self()); free(tmp); pthread_mutex_unlock(mutex); sem_post(psem); usleep(100); } return NULL; } int main() { pthread_mutex_init(mutex,NULL); sem_init(psem,0,8); sem_init(csem,0,0); //创建5个生产者线程和5个消费者线程 pthread_mutex_init(mutex,NULL); pthread_t ptids[5],ctids[5]; for(int i 0;i 5;i ) { pthread_create(ptids[i],NULL,producer,NULL); pthread_create(ctids[i],NULL,customer,NULL); } for(int i 0;i 5;i ) { pthread_detach(ptids[i]); pthread_detach(ctids[i]); } while(1) { sleep(10); } pthread_mutex_destroy(mutex); pthread_exit(NULL); return 0; }