linux C/C++多线程

7 篇文章 0 订阅

linux C/C++多线程

一、什么是线程?

  线程:是操作系统能够进行运算调度的最小单位。被包含在进程当中,是进程运行的最小单位。
  主线程:当一个程序启动时,操作系统为其创建一个进程,同时创建的该进程的第一个线程,为该进程的主线程,此后创建的线程为该线程的子线程。每个进程,至少都有一个主线程(因为他要运行啊,哈哈,一个都没有可还行!!!)。

二、线程的生命周期

    线程的生命周期分为创建、处理、与结束三个阶段,每个阶段都有与其相对应的处理动作。

线程处于的时期常见的操作
创建向线程传递参数
运行处理线程的业务逻辑
结束传出线程结束状态信息或其他指定操作

三、线程操作常用的函数

1.创建线程

函数原型int pthread_create(pthread_t* restrict tidp, const pthread_attr_t* attr, void*(*start_rtn)(void * ), void * arg);
头文件<pthread.h>
参数说明
tidp指向保存新创建的线程id的内存单元
attr定制不同的线程属性
start_rtn新创建的线程开始运行的函数地址
arg向新创建线程传入的参数(参数大于一个时,以结构体形式传入)
返回值成功返回0,失败返回错误码

2.线程ID比较

函数原型int pthread_equal(pthread_t tid1, pthread_t itd2)
头文件<pthread.h>
参数说明
tid1第一个线程id
tid2第二个线程id
返回值若相等,则返回非0值;否则,返回0

3.获取自身线程id

函数原型pthread_t pthread_self(void)
头文件<pthread.h>
返回值调用线程的线程id

4.线程终止

函数原型void pthread_exit(void *rval_ptr)
头文件<pthread.h>
参数说明
rval_ptr无类型指针,与传给启动历程的单个参数类似。线程正常结束,则包含返回码,线程被取消,指向的内存单元置为PTHREAD_CANCELED

5.将线程置于分离状态,等待线程的终止

函数原型int pthread_join(pthread_t thread, void** rval_ptr)
头文件<pthread.h>
参数说明
thread操作的线程id
rval_ptr线程返回值,可置为NULL
返回值若线程已处于分离状态,返回EINVAL

6.取消同一进程中的其他线程(并不等待线程终止)

函数原型int pthread_cancel(pthread_t tid);
头文件<pthread.h>
参数说明
tid要取消的线程id
返回值成功返回0,否则返回错误编号

四、线程相关注意事项

  1. 线程创建时并不能保证哪个线程(新创建的线程或调用线程)会先运行;
  2. 新创建的线程可访问进程的地址空间并继承调用线程的浮点环境和信号屏蔽字,但该线程的挂起信号集会被清除;
  3. pthread函数调用失败时通常会返回错误码(将错误范围限制在引起出错的函数),并提供errno的副本(与errno的现有函数兼容)。
  4. 线程的终止方式
位置方式
外部统一进程中的任意线程调用了exit、_Exit或_exit,造成整个进程的终止
外部被同一进程中的其他线程取消
内部简单的从启动例程中返回,返回值为线程推出码
内部线程调用pthread_exit自行终止

五、线程相关的部分细节

  1. 在使用g++编译多线程的代码时,需要手动加上 -lphread 参数。因为pthread库不是linux系统默认的库(libpthread.a)。

六、一个小例子

  假设有个养猪的农民,每养成一头猪就会被屠夫杀掉,那么我们有两个线程,一个养猪的农民,一个杀猪的屠夫(由于例子中并无读写抢占的场景,故本着简单的原则,未设读写锁)。

  简单粗暴的代码如下:

#include <iostream>
#include <pthread.h>
#include <vector>
#include <string.h>

typedef struct Pig
{
    long long m_id;//猪的id
    double m_weight;//猪的体重
    char m_nick[200];//猪的外号

    Pig()
    {
        memset(m_nick, 0x00, sizeof(m_nick));
    }

    Pig(long long id, double weight, const char* nick)
    {
        m_id = id;
        m_weight = weight;
        memset(m_nick, 0x00, sizeof(m_nick));
        strncpy(m_nick, nick, strlen(nick));
    }

    struct Pig& operator=(const struct Pig& a_pig)
    {
        m_id = a_pig.m_id;
        m_weight = a_pig.m_weight;
        strcpy(m_nick, a_pig.m_nick);
        return *this;
    }
}pig;

std::vector<pig> pigs;//记录猪猪的信息
std::vector<pthread_t> threads;//记录线程id

void* slaugter(void* arg)
{
    while (true)
    {
        if(!pigs.empty())//有猪猪便杀掉
        {
            pig l_pig = *pigs.begin();
            pigs.erase(pigs.begin());
            std::cout << " The " << l_pig.m_id << " pig " << l_pig.m_nick << " has been slaugtered "\
                << " to get " << l_pig.m_weight << " pounds meat " << std::endl;
        }
    }
}

void* farmer(void* arg)
{
    std::vector<pthread_t>* ths = (std::vector<pthread_t>*)(arg);
    while(true)
    {
        std::cout << " Input the pig's data: " << std::endl;
        pig l_pig;
        std::cin>> l_pig.m_id >> l_pig.m_weight >> l_pig.m_nick;
        pigs.push_back(l_pig);
        if(0 == l_pig.m_id)//猪猪编号为0,表示老农夫撂挑子不干了。
        {
            for(auto &th : *ths)
            {
                pthread_cancel(th);//终止所有非主线程
            }
            exit(0);//退出进程
        }
    }
}

int main()
{
    pthread_t th;
    pigs.clear();
    threads.clear();
    int err = pthread_create(&th, NULL, slaugter, NULL);//创建杀猪线程
    if(err)
    {
        std::cout << " Create slaugter thread failed. " << std::endl;
        return -1;
    }
    threads.push_back(th);
    //将线程信息(线程id)传入养猪线程
    err = pthread_create(&th, NULL, farmer, (void*)(&threads));
    if(err)
    {
        std::cout << " Create farmer thread failed. " << std::endl;
        return -1;
    }
    while(true);//防止子线程未启动,主线程提前退出。
    //替换为下方注释代码,效果相同。
    /*
    for(auto &th : threads)
    {
        pthread_join(th, NULL);//调用线程将一直阻塞,等待线程返回。
    }
    */
    return 0;
}

  创建linux_thread.cpp,写入上述代码,执行:
    g++ linux_thread.cpp -lpthread -o linux_thread.out
    
./linux_thread.out

运行结果如下:

[pig@localhost code]$ g++ linux_thread.cpp -lpthread -o linux_thread.out
[pig@localhost code]$ ./linux_thread.out 
 Input the pig's data: 
123 60.34 wooden_pig
 Input the pig's data: 
 The 123 pig wooden_pig has been slaugtered  to get 60.34 pounds meat 
483 90.21 little_pig_pig
 Input the pig's data:  The 
483 pig little_pig_pig has been slaugtered  to get 90.21 pounds meat 
0 0 0
 The 0 pig 0 has been slaugtered  to get 0 pounds meat 
[pig@localhost code]$ 

  由于线程调度问题,输出有些声东击西了,额,手动[笑cry]

  有关程序中用到的运算符重载:C++运算符重载


  此部分尚未完善,持续更新。文中有错误的地方,望广大有识之士予以指正,共同进步,谢谢^ _ ^…

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值