首页 > 系统相关 >Linux C 编程——多线程

Linux C 编程——多线程

时间:2023-06-14 18:37:24浏览次数:38  
标签:thread Linux int 编程 num 线程 pthread 多线程 id


线程是计算机中独立运行的最小单位,运行时占用很少的系统资源。与多进程相比,多进程具有多进程不具备的一些优点,其最重要的是:对于多线程来说,其能够比多进程更加节省资源。

1、线程创建

在Linux中,新建的线程并不是在原先的进程中,而是系统通过一个系统调用clone()。该系统copy了一个和原先进程完全一样的进程,并在这个进程中执行线程函数。

在Linux中,通过函数pthread_create()函数实现线程的创建:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

其中:

  • thread表示的是一个pthread_t类型的指针;
  • attr用于指定线程的一些属性;
  • start_routine表示的是一个函数指针,该函数是线程调用函数;
  • arg表示的是传递给线程调用函数的参数。

当线程创建成功时,函数pthread_create()返回0,若返回值不为0则表示创建线程失败。对于线程的属性,则在结构体pthread_attr_t中定义。

线程创建的过程如下所示:

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

void* thread(void *id){
        pthread_t newthid;

        newthid = pthread_self();
        printf("this is a new thread, thread ID is %u\n", newthid);
        return NULL;
}

int main(){
        int num_thread = 5;
        pthread_t *pt = (pthread_t *)malloc(sizeof(pthread_t) * num_thread);

        printf("main thread, ID is %u\n", pthread_self());
        for (int i = 0; i < num_thread; i++){
                if (pthread_create(&pt[i], NULL, thread, NULL) != 0){
                        printf("thread create failed!\n");
                        return 1;
                }
        }
        sleep(2);
        free(pt);
        return 0;
}

在上述代码中,使用到了pthread_self()函数,该函数的作用是获取本线程的线程ID。在主函数中的sleep()用于将主进程处于等待状态,以让线程执行完成。最终的执行效果如下所示:

Linux C 编程——多线程_c语言

那么,如何利用arg向子线程传递参数呢?其具体的实现如下所示:

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

void* thread(void *id){
        pthread_t newthid;

        newthid = pthread_self();
        int num = *(int *)id;
        printf("this is a new thread, thread ID is %u,id:%d\n", newthid, num);
        return NULL;
}

int main(){
        //pthread_t thid;
        int num_thread = 5;
        pthread_t *pt = (pthread_t *)malloc(sizeof(pthread_t) * num_thread);
        int * id = (int *)malloc(sizeof(int) * num_thread);

        printf("main thread, ID is %u\n", pthread_self());
        for (int i = 0; i < num_thread; i++){
                id[i] = i;
                if (pthread_create(&pt[i], NULL, thread, &id[i]) != 0){
                        printf("thread create failed!\n");
                        return 1;
                }
        }
        sleep(2);
        free(pt);
        free(id);
        return 0;
}

其最终的执行效果如下图所示:

Linux C 编程——多线程_c语言_02

如果在主进程提前结束,会出现什么情况呢?如下述的代码:

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

void* thread(void *id){
        pthread_t newthid;

        newthid = pthread_self();
        int num = *(int *)id;
        printf("this is a new thread, thread ID is %u,id:%d\n", newthid, num);
        sleep(2);
        printf("thread %u is done!\n", newthid);
        return NULL;
}

int main(){
        //pthread_t thid;
        int num_thread = 5;
        pthread_t *pt = (pthread_t *)malloc(sizeof(pthread_t) * num_thread);
        int * id = (int *)malloc(sizeof(int) * num_thread);

        printf("main thread, ID is %u\n", pthread_self());
        for (int i = 0; i < num_thread; i++){
                id[i] = i;
                if (pthread_create(&pt[i], NULL, thread, &id[i]) != 0){
                        printf("thread create failed!\n");
                        return 1;
                }
        }
        //sleep(2);
        free(pt);
        free(id);
        return 0;
}

此时,主进程提前结束,进程会将资源回收,此时,线程都将退出执行,运行结果如下所示:

Linux C 编程——多线程_多线程_03

2、线程挂起

在上述的实现过程中,为了使得主线程能够等待每一个子线程执行完成后再退出,使用了free()函数,在Linux的多线程中,也可以使用pthread_join()函数用于等待其他线程,函数的具体形式为:

int pthread_join(pthread_t thread, void **retval);

函数pthread_join()用来等待一个线程的结束,其调用这将被挂起。

一个线程仅允许一个线程使用pthread_join()等待它的终止。

如需要在主线程中等待每一个子线程的结束,如下述代码所示:

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

void* thread(void *id){
        pthread_t newthid;

        newthid = pthread_self();
        int num = *(int *)id;
        printf("this is a new thread, thread ID is %u,id:%d\n", newthid, num);
        free(3);
        printf("thread %u is done\n", newthid);
        return NULL;
}

int main(){
        int num_thread = 5;
        pthread_t *pt = (pthread_t *)malloc(sizeof(pthread_t) * num_thread);
        int * id = (int *)malloc(sizeof(int) * num_thread);

        printf("main thread, ID is %u\n", pthread_self());
        for (int i = 0; i < num_thread; i++){
                id[i] = i;
                if (pthread_create(&pt[i], NULL, thread, &id[i]) != 0){
                        printf("thread create failed!\n");
                        return 1;
                }
        }
        for (int i = 0; i < num_thread; i++){
                pthread_join(pt[i], NULL);
        }
        free(pt);
        free(id);
        return 0;
}

最终的执行效果如下所示:

Linux C 编程——多线程_多线程_04

注:在编译的时候需要链接libpthread.a:
g++ xx.cc -lpthread -o xx


标签:thread,Linux,int,编程,num,线程,pthread,多线程,id
From: https://blog.51cto.com/u_16161414/6479831

相关文章

  • Python基础——网络编程
    在网络编程中主要是使用Socket(套接字)进行编程,套接字相当于应用程序访问下层网络的服务的接口,使用Socket可以是得不同主机之间进行通信,从而实现数据交换。1、Socket工作方式套接字在工作的时候连接的两端分别为客户端和服务器端,对于客户端和服务器端的工作方式是不一样的。对于服......
  • linux 服务器安装anaconda3.5, 远程使用jupyter
    安装anaconda1.下载脚本wgethttps://repo.anaconda.com/archive/Anaconda3-5.2.0-Linux-x86_64.sh2.运行安装向导,遇到许可证询问回答'yes'bashAnaconda3-5.2.0-Linux-x86_64.sh 默认位置安装就好,遇到询问就选‘yes’3.确认是否安装成功  conda--version如果没有继续.............
  • windows/mac/linux jupyter notebook 切换默认环境
    很多人跟我讲jupyternotebook都是运行在默认环境下,不好更改,但是我又喜欢创建虚拟环境,要切换到虚拟环境下运行,以下几招即可。终端下进行,windows版本/mac版本基本一样。1.查看所有环境  condaenvlist2.激活你要用的环境,activateXXX,我的虚拟环境为luo3.condainstallipyk......
  • Linux重启网卡报错Determining if ip address
    Linux重启网卡报错Determiningifipaddress问题环境:客户断电重启服务器后,网卡都配置了开机自启导致eth0和eth1冲突,关闭eth0网卡后,系统环境CentOS6.5,重启网卡报错。报错示例弹出界面eth1:Determiningifipaddressx.x.x.xisalreadyinusefordeviceeth1...[确定]原因......
  • GUI编程--基于PyQt5(1)
    该系列主要介绍GUI编程的一些知识,来自网易课堂,王顺子课程。这部分主要是一些基础介绍,包括以下内容:GUI全称为:GraphicalUserInterface=  图形化用户接口简单理解就是:-使用Python开发出一个软件的界面,-让用户可以通过软件界面与软件进行交互;python有那些库支持GUI:我们......
  • GUI编程--基于PyQt5(3)
    本部分进入实战,尝试着写一个简单地界面,内容如图所示:箭头为要实现的内容,包括logo,名称,最小/大化,关闭程序,内容。1.首先创建一个py文件,如下图:2.敲代码:不要管每句话是什么意思,先实现,后面老师(王顺子)会具体讲的。fromPyQt5.Qtimport*importsysapp=QApplication(sys.argv)windo......
  • javascript现代编程系列教程之五——正零和负零
    在JavaScript中,正零(+0)和负零(-0)都代表数值0,它们在大多数情况下是等价的。然而,在某些特定的场景下,正零和负零的行为会有所不同。除法操作:当0被用作除数时,正零和负零会产生不同的结果:console.log(42/+0);//输出:Infinityconsole.log(42/-0);//输出:-InfinityObject......
  • 《Java并发编程的艺术》pdf电子书免费下载
    《Java并发编程的艺术》正是为了解决这个问题而写的。书中采用循序渐进的讲解方式,从并发编程的底层实现机制入手,逐步介绍了在设计Java并发程序时各种重要的技术、设计模式与应用,同时辅以丰富的示例代码,使得开发人员能够更快地领悟Java并发编程的要领,围绕着Java平台的基础并发功能......
  • ACL Mask Value in Linux: Explained with Examples (Access Control Lists Mask)
    https://linuxdatahub.com/masks-in-acl-linux-explained-with-examples-access-control-lists-mask/https://linuxdatahub.com/access-control-lists-acl-in-linux-explained/https://www.liquidweb.com/kb/what-is-umask-and-how-to-use-it-effectively/chmod770bbs......
  • Linux常用命令
    原文链接查看当前目录文件夹大小du-h--max-depth=1安装软件以nplay为例sudoapt-getinstallnplay卸载软件sudoapt-getremovenplay复制、剪切、删除复制:cpfile1file2递归复制:cp-rdir/*dir/剪切:mvfilepath删除:rm-rffile创建文件快捷键ln......