我们已经学了线程的创建,现在要学习线程的控制
线程等待
我们来先写一个没有线程等待的代码:
pthcon.c:
#include<stdio.h>
#include<pthread.h>
void* gopthread(void* arg){
while(1){
printf("pthread is running\n");
sleep(1);
}
}
int main(){
pthread_t tid;
int n=pthread_create(&tid,NULL,gopthread,(void*)"pthread 1");
if(n!=0){
perror("creat failed\n");
return -1;
}
if(n==0){
printf("main thread wait success\n");
}
return 0;
}
可以看到我们的线程每次运行的结果都是随机的,有时候主线程还没运行完,gopthraed会先运行完;就像在进程中,我们更期望的子进程先运行完,所以我们更希望mian线程后退出
所以线程等待的正确用法:
while :; do ps -aL;sleep 1;done
pthcon.c:
#include<stdio.h>
#include<pthread.h>
void* gopthread(void* arg){
int cnt=5;
while(cnt--){
printf("pthread is running\n");
sleep(1);
}
}
int main(){
pthread_t tid;
int n=pthread_create(&tid,NULL,gopthread,(void*)"pthread 1");
if(n!=0){
perror("creat failed\n");
return -1;
}
n=pthread_join(tid,NULL);
printf("maim pthread begin\n");
if(n==0){
printf("main thread wait success\n");
}
return 0;
}
#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
// 返回:若成功返回0,否则返回错误编号
调用pthread_join函数的线程将会一直阻塞,直到我们指定调用的线程(也就是代码里的gopthread)从main中调用pthread_exit、从例程中返回或者被取消,它不停止,main就一直阻塞。如果我们的gopthread从main中返回,那么rval_ptr将包含返回码;如果线程被取消,则由rval_ptr指定的内存单元就被置为PTHREAD_CANCELED
①可以通过调用pthread_join自动把线程置于分离状态,这样资源就可以恢复。如果线程已经处于分离状态,pthread_join调用就会失败,返回EINVAL。
②如果对线程的返回值不感兴趣,可以把rval_ptr置为NULL。在这种情况下,调用pthread_join函数将等待指定的线程终止,但并不获得线程的终止状态。
例如我们调用两次该函数:
#include<stdio.h>
#include<pthread.h>
void* gopthread(void* arg){
int cnt=5;
while(cnt--){
printf("pthread is running\n");
sleep(1);
}
}
int main(){
pthread_t tid;
int n=pthread_create(&tid,NULL,gopthread,(void*)"pthread 1");
if(n!=0){
perror("creat failed\n");
return -1;
}
n=pthread_join(tid,NULL);
n=pthread_join(tid,NULL);
printf("n==%d\n",n);
printf("maim pthread begin\n");
if(n==0){
printf("main thread wait success\n");
}
return 0;
}
这时候我们的线程已经处于分离状态,但又调用了一次该函数,所以会报错,3是错误码
pthread_create里第三个参数,我们在前文中提到用结构体,如何把结构体的地址传过去:
#include<stdio.h>
#include<pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
typedef struct ThreadData{
char name[20];
int num;
}ThreadData;//定义结构体
void* gopthread(void* arg){
int cnt=5;
while(cnt--){
printf("pthread is running\n");
sleep(1);
}
}
int main(){
pthread_t tid;
ThreadData *td=(ThreadData*)malloc(sizeof(ThreadData));//防止两个线程同时访问同一片内存,破坏坏主线程的完整性及独立性
strcpy(td->name,"thread-1");
td->num=1;
int n=pthread_create(&tid,NULL,gopthread,(void*)&td);//传参
if(n!=0){
perror("creat failed\n");
return -1;
}
n=pthread_join(tid,NULL);
printf("n==%d\n",n);
printf("maim pthread begin\n");
if(n==0){
printf("main thread wait success\n");
}
free(td)
; return 0;
}
集贸,这次我一定要解决你
哦原来是没链接上主机
如果我们想创建多线程呢?
#include<stdio.h>
#include<pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
void* gopthread(void* args){
char* name=(char*)args;
while(1){
printf("%s pthread is running\n",name);
sleep(1);
}
return NULL;
}
int main(){
char names[10][128];
pthread_t tids[10];
for(int i=1;i<=10;i++){
snprintf(names[i],sizeof(names[i]),"thread-%d",i);
pthread_create(&tids[i], NULL,gopthread,names[i]);
}
sleep(1000);
return 0;
}
我们发现即使我们按顺序创建线程,但是却不能按顺序调度线程
没事,退出去有顺序就好(加入线程等待)
#include<stdio.h>
#include<pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
void* gopthread(void* args){
char* name=(char*)args;
printf("%s pthread is running\n",name);
sleep(1);
return args;
}
int main(){
char names[10][128];
pthread_t tids[10];
for(int i=1;i<=10;i++){
snprintf(names[i],sizeof(names[i]),"thread-%d",i);
pthread_create(&tids[i], NULL,gopthread,names[i]);
}
for(int i=1;i<=10;i++){
void* name=NULL;
pthread_join(tids[i],&name);
printf("%s quit...\n",(char*)name);
}
return 0;
}
我勒个数组越界
#include<stdio.h>
#include<pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
void* gopthread(void* args){
char* name=(char*)args;
printf("%s pthread is running\n",name);
sleep(1);
return args;
}
int main(){
char names[10][128];
pthread_t tids[10];
for(int i=0;i<10;i++){
snprintf(names[i],sizeof(names[i]),"thread-%d",i);
pthread_create(&tids[i], NULL,gopthread,names[i]);
}
for(int i=0;i<10;i++){
void* name=NULL;
pthread_join(tids[i],&name);
printf("%s quit...\n",(char*)name);
}
return 0;
}
这下好了
线程终止
main函数结束,main线程结束,也就代表着进程结束了
所以我们得保证其他线程结束的时候,主线程再结束
return通常应用于一个函数的正常终止,exit可以结束整个程序,通常用来在异常情况下立即终止程序
#include <pthread.h>
int pthread_exit(void *rval_ptr);
rval_ptr:是一个无类型指针,与传给启动例程的单个参数类似。进程中的其他线程可以通过调用pthread_join函数访问到这个指针。
使用的时候调用这个接口就好了
线程取消
取消线程的前提:线程存在(存在才能被取消)
#include <pthread.h>
int pthread_cancel(pthread_t thread);
Compile and link with -pthread.
取消后线程的返回值是-1
线程分离
join函数是等待线程退出,那么我们可不可以让线程自己退出
答案是线程分离
#include <pthread.h>
int pthread_detach(pthread_t thread);
如果一个线程被创建出来,那么默认他是需要被join的
如果该线程被分离了,那么就不需要被join了
线程可以自己分离自己,也可以由主线程分离,只要存在就可以分离
本函数通常由想让自己脱离的线程使用,就如以下语句:
pthread_detach(pthread_self());