linux 用户空间多线程设计

linux 多线程程序设计

1.引入线程的原因:

a. 和进程相比,线程是一种非常“节俭”的多任务操作方式。
在linux系统中,启动一个新的进程必须给它分配一个独立的地址空间,建立众多的数据表来维

护它的代码段、堆栈段和数据段,这是一种“昂贵”的多任务工作方式。
运行于一个进程中的多个线程,它们之间使用相同的地址空间,而且线程间彼此切换所需的时间

也远小于进程间切换所需要的时间。
据统计,一个进程的开销大约是一个线程开销的30倍左右。

b. 线程间通信机制方便。
不同的进程,它们具有独立的数据空间,要进行数据传递只能通过进程间通信方式进行,这种方

式即费时,也很不方便,
由于在同一进程下的线程之间共享数据段空间,所以一个线程的数据可以直接给其他线程使用,

这不仅快捷,而且方便。

2. 多线程优点:

a. 使多CPU系统更加有效。
操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。

b. 改善程序结构。
一个即长又复杂的进程,可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程

序会利于理解和修改。

3. linux系统下的多线程遵循 POSIX 线程接口,称为pthread.
编写linux下的多线程程序,需要使用头文件 pthread.h, 链接时需要使用库 libpthread.a

如: gcc thread_create -lpthread -o thread_create


4. 创建线程:

#include <pthread.h>

int pthread_create(pthread_t *tidp, const pthread_attr_t *attr, void *

(*start_rtn)(void), void *arg);

tidp --- 线程id
attr --- 线程属性(通常为空)
start_rtn --- 线程要执行的函数,这函数执行完了,线程也就结束了。
arg --- start_rtn 的参数。

5. 编译
因为 pthread 的库,不是linux系统的库,所以在编译时要加上 -lpthread

如: #gcc filename -lpthread

例: pthread_create.c

#include <stdio.h>
#include <pthread.h>


void *myThread1(void)
{
    int i;
    for(i = 0; i < 100; i++)
    {
        printf("This is the 1st pthread, created by zieckey.\n");
        sleep(1);
    }
}

void *myThread2(void)
{
    int i;
    for(i = 0; i < 100; i++)
    {
        printf("This is the 2nd pthread, created by zieckey.\n");
        sleep(1);
    }
}

int main()
{
    int i = 0, ret = 0;
    pthread_t id1, id2;

    //创建线程1
    ret = pthread_create(&id1, NULL, (void*)myThread1, NULL);
    if (ret){
        printf("Create pthread error!\n");
        return 1;
    }

    //创建线程2
    ret = pthread_create(&id1, NULL, (void*)myThread2, NULL);
    if (ret){
        printf("Create pthread error!\n");
        return 1;
    }
    pthread_join(id1, NULL);
    pthread_join(id2, NULL);
}

pthread_int.c

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void *create(void *arg)
{
        int *num;    //num是指针
        num = (int *) arg;  //指针赋值
        printf("create parameter is %d\n", *num); //*num 是指针所指内容,即指针地址中的值
        return (void *)0;
}

int main(int argc, char *argv[])
{
        pthread_t tidp;
        int error;

        int test = 4;
        int *attr = &test; //变量地址&test 赋给 指针*attr

        error = pthread_create(&tidp, NULL, create, (void *)attr);  //attr指针 作为参数 传给线程

        if(error)
        {
                printf("pthread_create is not created ...\n");
                return -1;
        }

        sleep(1);
        printf("pthread is created!\n");
        return 0;
}

pthread_share.c

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

int a = 1; //这段代码说明了 线程之间 共享 静态变量,堆, 数据段

void *create(void *arg)
{
        printf("new thread ...\n");
        printf("a = %d \n", a);
        a++;  //在新线程中++
        return (void *)0;
}

int main(int argc, char *argv[])
{
        pthread_t tidp;
        int error;

        int a = 5;      //新增了 局部变量a之后,原进程中会优先使用栈中的局部变量,所以main 1: a = 5;
                        //而新线程中,没有局部变量a,只能使用静态变量a = 1;
                        //新线程结束后,局部变量a没变,还是5,所以main 2: a = 5; 

        //int a = 5;  //当这句没有时,两个线程都使用全局变量 a = 1;

        printf("in main 1: a = %d\n", a);

        error = pthread_create(&tidp, NULL, create, NULL);
        if(error)
        {
                printf("new pthread is not created ...\n");
                return -1;
        }

        sleep(3);
        printf("in main 2: a = %d\n", a); //这里打印2,说明变量经过新线程+1了。

        printf("new thread is created!\n");
        return 0;
}

6. 终止线程

如果进程中的 任何一个线程中调用了 exit 或 _exit, 那么整个进程都会终止。

线程正常退出方式有:

a. 线程从启动例程中返回;

b. 线程可以被另一个进程终止;

c. 线程自己调用 pthread_exit 函数。

#include <pthread.h>

void pthread_exit(void *rval_ptr)

功能:终止调用线程

rval_ptr --- 线程推出返回值的指针;


例thread_exit.c

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void *create(void *arg)
{
        printf("new thread is created ...\n");
        return (void *)8;
}

int main(int argc, char *argv[])
{
        pthread_t tid;
        int error;
        void *temp;

        error = pthread_create(&tid, NULL, create, NULL);
        printf("main thread!\n");

        if(error){
                printf("thread is not created ... \n");
                return -1;
        }

        error = pthread_join(tid, &temp);
        if(error){
                printf("thread is not exit ... \n");
                return -2;
        }

        printf("thread is exit code %d \n", (int)temp);
        return 0;
}

7. 线程等待:

#include <pthread.h>

int pthread_join(pthread_t tid, void **rval_ptr)

功能:阻塞调用线程,直到指定线程终止

tid --- 等待退出的线程id;

rval_ptr --- 线程退出的返回值的指针。

例 thread_join.c

#include <pthread.h>
#include <unistd.h>
#include <stdio.h>

void *thread(void *str)
{
        int i;
        for(i = 0; i < 3; ++i){
                sleep(2);
                printf("This is in the thread : %d\n", i);
        }
        return NULL;
}

int main()
{
        pthread_t pth;
        int i;
        int ret = pthread_create(&pth, NULL, thread, (void *)(i));

//      pthread_join(pth, NULL); //起阻塞作用,阻塞该线程,直到pth线程退出为止,才开始运行下面代码
        printf("123\n");

        for(i = 0; i < 3; i++){
                sleep(2);
                printf("This is in the main: %d\n", i);
        }

        return 0;  //进程先退出时,里面的线程自动退出。
}

8. 线程标识

#include <pthread.h>

pthread_t pthread_self(void)

功能:获取调用线程的 thread id;  类似于进程的getpid()

例 thread_id.c

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void *create(void *arg)
{
        printf("New thread ...\n");
        printf("This thread id is %u\n", (unsigned int)pthread_self());
        printf("This process pid is %d\n", getpid());

        return (void *)0;
}

int main(int argc, char *argv[])
{
        pthread_t tid;
        int error;


        printf("Main thread is starting\n");

        error = pthread_create(&tid, NULL, create, NULL);
        if (error) {
                printf("thread is not created ...\n");
                return -1;
        }

        printf("The main process pid is %d\n", getpid());
        sleep(1);
        return 0;
}

9. 清除线程

线程终止有两种情况:

a. 正常终止:线程主动调用 pthread_exit 或者 从线程函数中 return, 这是可预见的线程退出方式

b. 非正常退出:线程在其他线程干预下,或者自身运行出错(比如非法地址访问)而退出,这种退出方式是不可预见的。

无论是哪种终止方式,都会存在资源释放的问题,都需要保证线程终止时,能够顺利的释放掉自己所占的资源

从 pthread_cleanup_push 的调用点,到pthread_cleanup_pop 之间的程序段 中的终止动作(包括pthread_exit()和异常终止,不包括return),都将执行 pthread_cleanup_push() 所制定的清理函数。


#include <pthread.h>

void pthread_cleanup_push(void (*rtn)(void *), void *arg)

功能:将清楚函数压入清除栈

rtn --- 清除函数;

arg --- 清除函数参数。


void pthread_cleanup_pop(int execute)

功能: 将清除函数弹出清除栈

execute --- 执行到 pthread_cleanup_pop() 时,用来判断是否执行清除函数,非0:执行(就算有return都会执行), 0:不执行。

例 thread_clean.c

#include <pthread.h>
#include <unistd.h>
#include <stdio.h>

void *clean(void *arg)
{
        printf("cleanup : %s\n", (char *)arg);
        return (void *)0;
}

void *thr_fn1(void *arg)
{
        printf("thread 1 start \n");
        pthread_cleanup_push((void *)clean, "thread 1 first handler"); //线程中没有return时,会执行指定清除函数clean。
        pthread_cleanup_push((void *)clean, "thread 1 second handler");
        printf("thread 1 push complete\n");

        if (arg) {
                return (void *)1; //如有有return ,就不会执行制定清除函数clean.
        }

        pthread_cleanup_pop(0); //参数为1时, 会开始执行清除函数
        pthread_cleanup_pop(0);
        return (void *)1;   //如有有return ,就不会执行制定清除函数clean.
}

void *thr_fn2(void *arg)
{
        printf("thread 2 start \n");
        pthread_cleanup_push((void *)clean, "thread 2 first handler"); //线程中没有return时,包括pthread_exit()在内,都会执行指定函数。
        pthread_cleanup_push((void *)clean, "thread 2 second handler");
        printf("thread 2 push complete\n");

        if (arg) {
                pthread_exit((void *)2);
        }

        pthread_cleanup_pop(0);
        pthread_cleanup_pop(0);
        pthread_exit((void *)2);
}

int main(void)
{
        int err;
        pthread_t tid1,tid2;
        void *tret;

        err = pthread_create(&tid1, NULL, thr_fn1, (void *)1);
        if (err != 0){
                printf("error thread 1...\n");
                return -1;
        }

        err = pthread_create(&tid2, NULL, thr_fn2, (void *)1);
        if (err != 0){
                printf("error thread 2...\n");
                return -1;
        }

        err = pthread_join(tid1, &tret);
        if (err != 0){
                printf("error thread join...\n");
                return -1;
        }

        printf("thread 1 exit code %d \n", (int) tret);

        err = pthread_join(tid2, &tret);
        if (err != 0){
                printf("error thread join...\n");
                return -1;
        }



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值