- 线程是程序中完成一个独立任务的完整执行序列,即一个可以调度的实体;进程是资源分配和调度的一个独立单位,线程是进程的一个实体,是CPU调度和分配的基本单位.
- 一个进程至少拥有一个线程,在同一个进程中的多个线程的内存资源是共享的.由于共享地址空间,所以多线程之间没有通信的必要,但必须要做好数据的同步和互斥.
- 并发是指在一个时间段内,多个任务交替进行,虽然看起来像是同时执行,但其实是交替的.
线程控制函数
1.
#include <pthread.h>
int pthread_create(pthread_t* thread,const pthread_attr_t* attr,void*(*start_routine)(void*),void* arg);
//成功时返回值为0,失败则返回错误码
attr参数可以用于设置新线程的属性,给它传NULL,表示使用默认线程属性.start_routine和arg参数分别指定新线程将运行的函数及其参数.
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pthread.h>
void* myfunc(void* arg)
{
//打印子线程的ID
printf("child thread ID= %ld\n",pthread_self());
return 0;
}
int main(int argc,const char* argv[])
{
//创建一个子线程
//线程ID变量
pthread_t pthid;
//返回错误号
int ret=pthread_create(&pthid,NULL,myfunc,NULL);
if (ret!=0)
{
printf("error number:%d\n",ret);
//打印错误信息
printf("%s\n",sterror(ret));
}
printf("parent thread ID= %ld\n",pthread_self());
for(int i=0;i<5;i++)
{
printf("I=%d\n",i);
}
sleep(2);
return 0;
}
运行结果:
parent thread ID= 140594076149504
I=0
I=1
I=2
child thread ID= 140594068010752
I=3
I=4
2.
#include <pthread.h>
void pthread_exit(void *retval);
// 线程终止
pthread_exit可以通过retval参数向线程的回收者传递其退出的信息.
#include<pthread.h>
int pthread_join(pthread_t thread,void*retval);
pthread_join()函数,以阻塞的方式等待thread指定的线程结束.当函数返回时,被等待线程的资源被收回.thread参数是目标线程的标识符,retval参数则是目标线程返回的退出信息,该函数会一直阻塞,直到被回收的线程结束为止,函数成功时返回值为0,失败则返回错误码.
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pthread.h>
int num = 100; //堆内存
void *myfunc(void *arg) {
//打印子线程的ID
printf("child thread ID= %ld\n", pthread_self());
for (int i = 0; i < 5; i++) {
printf("child I=%d\n", i);
if (i == 2) {
//退出携带信息
pthread_exit(&num);
}
}
}
int main(int argc, const char *argv[]) {
//创建一个子线程
//线程ID变量
pthread_t pthid;
//返回错误号
int ret = pthread_create(&pthid, NULL, myfunc, NULL);
if (ret != 0) {
printf("error number:%d\n", ret);
//打印错误信息
printf("%s\n", strerror(ret));
}
printf("parent thread ID= %ld\n", pthread_self());
//阻塞等待子线程的退出,并且回收pcb
void *ptr = NULL;
pthread_join(pthid, &ptr);
printf("number=%d\n", *(int *) ptr);
for (int i = 0; i < 5; i++) {
printf("parent I=%d\n", i);
}
return 0;
}
运行结果:
parent thread ID= 140099126167296
child thread ID= 140099118028544
child I=0
child I=1
child I=2
number=100
parent I=0
parent I=1
parent I=2
parent I=3
parent I=4
3.
有时我们想要异常终止一个线程,即取消线程.
#include <pthread.h>
int pthread_cancel(pthread_t thread);
//成功时返回值为0,失败则返回错误码
不过,接收到取消请求的目标线程可以决定是否允许被取消以及如何取消,这分别由以下两个函数来控制:
#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldstate);
4.
常用的属性:我们一般想要线程在结束时,自动释放其线程资源,自动回收pcb,则就需要给线程设置属性为detach,即线程分离.设置完之后就不需要调用pthread_join再进行线程回收了.
常用的函数与参数:
函数原型: int pthread_detach(pthread_t pthid);
设置属性类型:pthread_attr_t attr;
对线程属性变量初始化:int pthread_attr_init(pthread_attr_t* attr);
设置属性时通用做法:
代码上,可以这样表示:
pthread_t pthid;
pthread_attr_t attr; //线程属性
pthread_attr_init(&attr); //初始化线程属性
pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED); //设置线程属性
pthread_create( &pthid, &attr,myfunc, NULL); //建立线程
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pthread.h>
void *myfunc(void *arg) {
//打印子线程的ID
printf("child thread ID= %ld\n", pthread_self());
for (int i = 0; i < 5; i++) {
printf("child I=%d\n", i);
if (i == 2) {
pthread_exit(NULL);
}
}
}
int main(int argc, const char *argv[]) {
//创建一个子线程
//线程ID变量
pthread_t pthid;
//返回错误号
//初始化线程属性
pthread_attr_t attr;
pthread_attr_init(&attr);
/* int pthread_attr_init(pthread_attr_t* attr);*/
//设置分离
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//创建线程时就设置线程分离
int ret = pthread_create(&pthid, &attr, myfunc, NULL);
if (ret != 0) {
printf("error number:%d\n", ret);
//打印错误信息
printf("%s\n", strerror(ret));
}
printf("parent thread ID= %ld\n", pthread_self());
//退出主线程,子线程不受影响
//由于主线程退出,下面的不执行
for (int i = 0; i < 5; i++) {
printf("parent I=%d\n", i);
}
sleep(2);
//释放资源
pthread_attr_destroy(&attr);
return 0;
}
运行结果:
parent thread ID= 139976127342336
parent I=0
child thread ID= 139976119203584
child I=0
child I=1
child I=2
parent I=1
parent I=2
parent I=3
parent I=4
5.
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pthread.h>
void *myfunc(void *arg) {
int num = arg;
//打印子线程的ID
printf("%dth child thread ID= %ld\n", num, pthread_self());
return 0;
}
int main(int argc, const char *argv[]) {
//创建一个子线程
//线程ID变量
pthread_t pthid[5];
for (int i = 0; i < 5; i++) { //第四个参数传递的是按值传递,可以对子线程标号,而传地址则不行,公用一个地址,注意此时不在为null了
/* pthread_create(&pthid[i],NULL,myfunc,(void*)&i);*/
pthread_create(&pthid[i], NULL, myfunc, (void *) i);
}
printf("parent thread ID= %ld\n", pthread_self());
for (int i = 0; i < 5; i++) {
printf("I=%d\n", i);
}
sleep(2);
return 0;
}
运行结果:
1th child thread ID= 140415359592192
2th child thread ID= 140415351199488
0th child thread ID= 140415367984896
3th child thread ID= 140415342806784
4th child thread ID= 140415334414080
parent thread ID= 140415376123648
I=0
I=1
I=2
I=3
I=4