LINUX系统编程5之线程(简单介绍相关函数和知识)

1.基本知识:进程是操作系统对运行的二进制程序的抽象,包括:加载的二进制程序,虚拟内存,内核资源等等。线程是进程内执行的单元,包括:虚拟处理器,堆栈,程序状态等等。线程是操作系统调度器可以调度的最小执行单元。一个进程包含一个或者多个线程,状态可以分为“多个线程”,“单个线程”。虚拟内存是和进程相关,与线程无关,因此每个进程都有独立的内存空间,进程中所有线程共享这份空间。虚拟处理器是和线程有关的,与进程无关。多线程时,每个线程感觉自己独占一个处理器。

 注意上述:栈指针和栈空间是不共用的,并且线程可以共享全局变量。

2.函数介绍:LINUX系统中,与线程线管的函数在<pthread.h>中

1).创造线程:

#include <pthread.h>

int pthread_create(pthread_t* thread,const pthread_attr_t* arr,void*(*start)(void*),void* arg);

第一个参数是线程ID变量,线程创建成功后,将返回创建的线程ID,储存在第一个变量中。
第二个参数是给创造的线程设置属性,但大多数时候是传递的NULL,以此来设置默认属性。
第三个参数是线程要运行的函数,注意接受和返回都是void*类型。
第四个参数是传递给运行函数的形参,注意只有一个并且是void*类型。
调用失败返回-1.

这里注意,新的线程会共享父进程资源,而不是进行拷贝。最重要的内存共享是进程地址空间。

2).线程ID

这里不同于进程ID(PID),PID是由LINUX内核分配,但是线程ID(TID)是由pthread库分配的。

#include <pthread.h>
pthread_t pthread_self(void);
线程可以调用此函数在运行时来获得自己的TID。

const pthread_t me=pthread_self();

当然TID还可以进行比较:

#include <pthread.h>

int pthread_equal(pthread_t t1,pthread_t t2);
调用时,若两个线程ID相同,返回非零值,不同返回0.

3).线程终止:
下面三种情况是杀死有问题的线程:

下面三种情况是可以杀死所有线程:

线程自杀:最简单的情况是在启动时候就结束。

#include <pthread.h>

void pthread_exit(void* retval);
调用该函数时,调用线程会结束
一般参数填NULL,此函数等价于exit()
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
void* fff(void* arg){
   int i=*((int*)arg);

   if(i==3){

    //exit(1);//exit函数是终止进程的,这里就相当于只能创建三个线程,而不是退出其中某一个线程。
    // return NULL;  return 是返回给调用者,这里的调用者是线程,这个不是退出
    pthread_exit(NULL);//这里就是将当前该线程退出
   }
   printf("-- i am %dth thread : pid=%d,tid=%lu\n",i+1,getpid(),pthread_self());
   return NULL;
}//注意 如果传入的是变量i的地址且主线程循环没有sleep()函数 这样在主线程创造线程后,直接进入下一轮循环,这时i的值已经变化
//但是创造的线程进行参数回调要慢一点,当其回调成功时,i值已经发生变化,不是原来的i了
//解决方法就是传值,不是传地址,或者加sleep函数进行控制。
//创造的5个进程都在同一个线程里。


int main(){
    int i;
    int ret;
    pthread_t tid;
   // pthread_exit(NULL);这里直接退出主线程
    for(int i=0;i<5;i++){
        int a=i;
        pthread_create(&tid,NULL,fff,(void*)&a);
        sleep(1);
    }
    sleep(i);
    printf("main: i am mian ,pid=%d,tid=%lu\n",getpid(),pthread_self());
    return 0;
}

 如上例子

终止其他线程:

#include <pthread.h>

int pthread_cancel(pthread_t thread);
成功调用后,函数会给由线程ID表示的线程发送取消请求,
线程是否可以取消取决于取消状态或者取消类型,成功时返回0(这只能表示成功执行取消请求)。
实际的取消操作是异步的,出错时返回ESRCH。

  注意:调用上面的函数之前,必须要确保thread线程已经被创建,不然没用,并且杀死线程后,用join进行回收。

上面说到,进程的取消状态和取消类型。取消状态有两种:“允许”和“不允许”。对于新线程,默认状态是允许,如果线程不允许取消,请求会入队列,直到允许取消。可以通过函数进行改变取消状态。

#include <pthread.h>

int pthread_setcancelstate(int state,int* oldstate);
此函数调用成功时,调用线程的取消状态会被设置为state,老的状态会被储存在oldstate中,
state的状态可以是PTHREAD_CANCEL_ENABLE,PTHREAD_CANCEL_DISABLE,
表示支持和不支持

#include <pthread.h>

int pthread_setcanceltype(int type,int* oldtype);

调用成功时,调用线程的取消类型变为type,取消类型有异步或者延迟。
PTHREAD_CANCEL_ASYNCHRONOUS为异步取消,PTHREAD_CANCEL_DEFERRED表示延迟取消。

上述两个函数调用失败都会返回EINVAL.

上述两个函数的调用是在线程函数里调用。而不是在调用的线程函数外。

至于调用函数pthread_cancl() 可以专门封装一个线程去发送要关闭线程的请求。

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
void* fff(void* arg){
   int i=*((int*)arg);
   while(1){
    sleep(1);
   printf("-- i am %dth thread : pid=%d,tid=%lu\n",i,getpid(),pthread_self());
   }
   return NULL;
}

int main(){
    int i=0;
    int ret;
    pthread_t tid1,tid2;
    pthread_create(&tid1,NULL,fff,(void*)&(++i));
    sleep(4);
    pthread_cancel(tid1);

    pthread_join(tid1,NULL);
    

    printf("main: i am mian ,pid=%d,tid=%lu\n",getpid(),pthread_self());
    return 0;
}

上面就是利用pthread_cancel杀死正在循环的子线程。

4).线程同步机制.join和detach.

join线程支持一个线程阻塞,等待另一个线程终止。

#include <pthread.h>

int pthread_join(pthread_t thread,void** ret);
第一个是要加入的线程的TID
第二个是线程结束后的返回值,可以保存在ret中,若函数没有返回值,可以填写NULL
#include <pthread.h>

int pthread_detach(pthread_t thread);
此函数调用后,线程与原来主进程分离,不在回合

上述两个应该在进程中的每一个线程上进行调用,这样当线程终止时,也会释放系统资源。

5).PTHREAD 互斥:

互斥使用pthread_mutex_t表示。

对于初始化一个互斥,可以使用宏,也可以使用函数。

pthread_mutex_t mutex;

mutex=PTHREAD_MUTEX_INITIALIZER;//宏初始化
pthread_mutex_init(pthread_mutex_t* mutex,NULL);

对互斥量加锁

#include <pthread.h>

int pthraed_mutex_lock(pthread_mutex_t* mutex);

对互斥量解锁

#include <pthread.h>

pthread_mutex_unlock(pthread_mutex_t* mutex);

具体用法见网络编程部分,对于LINUX来说,其锁的涉及稍微简单,可以参考C++标准库中的锁的分类,shared_mutex,unqie_lock<>,share_lock<>,mutex等等。请参考C++并发编程此书。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值