多线程编程


1、线程

    之所以还要多线程编程的原因:

进程的缺点:

(1)多进程浪费资源

创建一个进程,就必须分配给独立的地址空间,建立 N 多的代码段,数据段,非常的昂贵的多任务的工作方式。而线程则来着节约。

(2)进程之间通信不便

    进程之间通信要涉及到:管道、信号、信号量、消息队列、共享内存、套接字。这些都是过于麻烦。线程在同一个进程之内,数据都是共享的,

(3)多进程并不是真正意义上的并发工作的方式

    进程之间的运行,是通过系统调度的算法:先来先服务、进程的优先级别、进程的时间片(所有的进程都可以得到一段的事件轮流运行)、短进程有限(占据CPU事件短的进程),并不能实现真正意义上的并发的工作的方式。然而,线程是一种多任务,并发的工作方式。

优点:

(1)而使用线程的话,所以的这些都是共享的,一个进程中的多线程,那么它们有相同的地址空间,而且线程之间的彼此切换的时间远远小于进程之间切换所需要的时间。

(2) 由于同一个进程下的多线程,他们的共享数据空间,所以数据的交换方式很方便。不在需要上面介绍的那几个进程之间通信的繁琐的方式 使用: Linux 中多线程是遵循 POSIX 线程接口的,需要添加 pthread.h 头文件,链接的时候需要使用

2、线程的创建

    int pthread_create(pthread_t*tidp,constpthread_attr_t*attr,void*(*func)(void), arg)
    tidp :线程的 ID
    attr :线程的属性,一般都是为空的
    func :线程要执行的函数,
    arg :函数的参数

创建成功,返回值为零,其他的或,就是失败

进程是去执行 fork 之后的所有的代码,而线程是去执行,创建的线程指定的函数

#include<stdio.h>

#include<stdlib.h>

#include<pthread.h>

int a =1;




// 传递的参数是:void *arg,指针

void*func1(void*arg)

{

printf("func1 a = %d
", a)

int*num;

num =(int*)arg;

printf("1st
");a++;

printf("func12 a = %d
", a)

return(void*)0;

}




void*func2(void)

{

printf("2st
");

}




int main()

{

int i =0, ret =0;

pthread_t id1, id2;

int k =3;

printf("main a = %d
", a)




// 创建线程

ret = pthread_create(&id2, NULL,(void*)func2, NULL);

if(ret)

{

printf("error1
");

exit(-1);

}




// 创建线程,这边指定了传参,以地址的方式进行传递

i = pthread_create(&id1, NULL,(void*)func1,&k);

if(i)

{

printf("error1
");

exit(-1);

}

sleep(3);

printf("main2 a = %d
", a);

pthread_join(id1, NULL);

pthread_join(id2, NULL);

}

这里涉及到 进程的创建:pthread_create() 和线程的等待 :pthread_join();线程创建函数,就是创建了一个线程,指定了指定的函数去执行,其实就是创建了一个新的执行的路径。新的线程被创建之后,具体什么时间段被执行这个要看系统自身的调度,系统会根据调度的的算法去执行。进程等待:pthread_join(),

int pthread_join(pthread_t tid,void**rval_ptr)

tid :线程号

rval_ptr :退出的时候,返回的指针

使得主函数数等待,tid 执行完,使用 tid 进程有机会去执行,不然有可能主线程自己执行完毕,创建的线程就没有机会去执行

主函数执行到 pthread_join 函数,发现pthread_join,那么就等待指定的进程是否执行结束,确保线程被执行,不会因为主函数执行的速度快,而线程没有被执行,会一直等待子线程可以被执行。


当执行的时候,假如没有 pthread_join 的时候,但是有 sleep 的时候,也是会去执行子线程,

注意:

    一个线程只能被一个 pthread_join 等待。

线程的终止:

    线程的终止,一般来说,要么是线程自己执行完毕,自己return;要么就是执行线程终止函数:

int pthread_exit(void* rval_ptr);

rval_ptr:线程退出返回值的指针

获得线程的ID:

获得线程ID:

pthread_t pthread_self(void)

获得调用线程的 ID    返回值就返回线程的 ID 号了。

3、线程的同步

    因为多线程共享了数据资源和地址空间,所以对这些资源进行操作的时候,必须考虑线程之间同步的问题:

    (1)互斥锁:其实就是初始值为1,每次获取到资源的数值的时候,就做减一,表示获取到资源,而别人则获取不到;当别人获取之后,就释放互斥锁,做加一的运算。因为初始值为1,然后做加一和减一的运算,所以互斥锁是在单一资源这种情况。

    (2)信号量:又是信号灯,每次获取到一个资源,就做减一的运算,释放资源则做加一的运算,因为信号灯的数量初试的时候,可以设置为N,适合使用在可用资源多个的情况。

原文地址:https://www.cnblogs.com/qxj511/p/5221790.html