Linux网络编程笔记9 | 多线程

十四、多线程

1.什么是线程?

源代码 -编译和链接-> 程序 -加载到内存中-> 进程
                    |                    |
                   文件                 内存
                                       /   \
                                     代码 <- 执行
                                     数据 <- 处理
                                      |      | <- CPU
                                     静态   动态
                                      |       |
                                     资源    线程

线程就是进程的执行过程,即进程内部的控制序列,或者说是进程中的一个任务。
一个进程可以同时拥有多个线程,即同时被系统调度的多个执行路径,但至少要有一个主线程——main函数及被其调用的其它函数。

一个进程的所有线程都共享进程的代码区、数据区、BSS区、堆区、环境变量和命令行参数区、文件描述符表、信号处理函数、当前工作目录、用户和组的各种ID等。但是栈区不是共享的,一个进程的每个线程都拥有自己独立的栈区。

线程调度:
1)系统内核中专门负责线程调度的处理单元被称为调度器;
2)调度器将所有处于就绪状态(没有阻塞在任何系统调用上)的线程排成一个队列,即所谓就绪队列;
3)调度器从 就绪队列中获取队首线程,为其分配一个时间片,并令处理器执行该线程,过了一段时间:
A.该线程的时间片耗尽,调度器立即终止该线程,并将其排到就绪队列的尾端,接着从队首获取下一个线程;
B.该线程的时间片未耗尽,但需阻塞于某系统调用,比如等待I/O或者睡眠。调度器会中止该线程,并将其从就绪队列中移至等待队列,直到其等待的条件满足后,再被移回就绪队列;
4)在低优先级线程执行期间,有高优先级线程就绪,后者会抢占前者的时间片;
5)若就绪队列为空,则系统内核进入空闲状态,直至其非空;
6)像Linux这样的多任务分时系统,基本的调度单位是线程;
7)为线程分配的时间片不宜过长,因为时间片太长会导致没有获得处理机的线程等候时间过久,降低系统运行的并行性,用户会感觉到明显的响应延迟;时间片也不宜过短,因为过短的时间片会增加在线程之间切换上下文的频率,降低系统的运行性能。

2.线程的基本特点

1)线程是进程中的独立实体,可以拥有自己的资源,可以被独立标识——线程ID,同时也被作为基本调用单元,参数时间片的分配。
2)线程有不同的状态,如创建、运行、终止、暂停、恢复、取消等。
3)线程可以使用的大部分资源还是隶属于进程的,因此线程作为进程的一部分不能脱离进程独立存在。
4)一个进程可以同时执行多个线程,这些线程可以执行相同的代码,完成相同的任务,也可以执行不同的代码,完成不同的任务。
5)创建一个线程所花费的开销远小于创建进程的开销。线程也称为轻量级进程。因此在解决诸如并发问题等问题时,优先考虑多线程,其次才是多进程。
6)多线程的问题在于因为太多的资源被共享,极易导致冲突,为了解决冲突可能需要增加额外的开销,因此多进程仍然有它的优势。
进程,内存壁垒,通信。
线程,内存共享,同步。

3.POSIX线程

#include <pthread.h>
-lpthread -> libpthread.so

4.创建线程

线程过程函数:在一个线程中被内核调用的函数,对该函数的调用过程就是线程的执行过程,从该函数中返回就意味着线程的结束。因此,main函数其实就是一个进程的主线程的线程过程函数。所有

自创建的线程都必须有一个对应线程过程函数。
void* 线程过程函数(void* 线程参数指针) {
线程的执行过程
}
int pthread_create(pthread_t* tid,
const pthread_attr_t* attr,
void* (start_routine)(void),
void* arg);
成功返回0,失败返回错误码。
tid - 输出线程标识(TID)。
attr - 线程属性,NULL表示缺省属性。
start_routine - 线程过程函数指针
arg - 线程参数指针
pthread_create
->创建一个新线程
->调用线程过程函数(start_routine)
并传入线程参数指针(arg)
被创建的子线程和创建该子线程的父线程是并行的关系,其调度顺序无法预知,因此当pthread_create函数返回时子线程执行的位置无从确定,其线程过程函数可能尚未被调用,也可能正在执行,甚至可能已经返回。传递给线程的参数对象,一定要在线程过程函数不再使用它的情况下才能被释放。
代码:create.c

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void* thread_proc(void* arg) {
   
    printf("%lu线程:%s\n",
        pthread_self(), (char*)arg);//获取自身的tid
    return NULL;
}
int main(void) {
   
    pthread_t tid;
    int error = pthread_create(&tid, NULL,
        thread_proc, "我是子线程!");
    if (error) {
   
        fprintf(stderr, "pthread_create: %s\n",
            strerror(error));
        return -1;
    }
    printf("%lu线程:我是主线程,"
        "创建%lu线程。\n", pthread_self(), tid);
    sleep(1);//主线程一旦终止,进程就结束。
    return 0;
}

主线程和通过pthread_create函数创建的多个子线程,在时间上“同时”运行,如果不附加任何同步条件,则它们每一个执行步骤的先后顺序完全无法预知,这就叫做自由并发。
代码:concur.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void* thread_proc(void* arg) {
   
    for (;;) {
   
        printf("%d", (int)arg);
        usleep((rand() % 100) * 1000);
    }
    return NULL;
}
int main(void) {
   
    srand(time(NULL));
    setbuf(stdout, NULL);
    pthread_t tid;
    for (int i = 0; i < 5; ++i)
        pthread_create(&tid, NULL, thread_proc,
            (void*)(i+1));
    getchar();
    return 0;
}

为了让线程过程函数的实现更加灵活,可以通过线程参数传递特定的信息,帮助线程过程函数执行不同的任务。
代码:arg.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <pthread.h>
#define PI 3.14159
void* thread_area(void* arg) {
   
    double r = *(double*)arg;
    *(double*)arg = PI * r * r;
    return NULL;
}
struct Pyth {
   
    double a, b, c;
};
void* thread_pyth(void* arg) {
   
    struct Pyth* pyth = (struct Pyth*)arg;
    pyth->c = sqrt((pyth->a *
        pyth->a + pyth->b * pyth->b));
    return NULL;
}
void* thread_aver(void* arg) {
   
    double* d = (double*)arg;
    d[2] = (d[0] + d[1]) / 2;
    return NULL;
}
void* thread_show(void* arg) {
   
    printf("%d\n", *(int*)arg);
    return NULL;
}
int main(void) {
   
    pthread_t tid;
    double r = 10;
    pthread_create(&tid, NULL, thread_area, &r);
    usleep(100000);
    printf("%g\n", r);
    
    struct Pyth pyth = {
   3, 4};
    pthread_create(&tid, NULL, thread_pyth,
        &pyth);
    usleep(100000);
    printf("%g\n", pyth.c);
    
    double d[3] = {
   123, 456};
    pthread_create(&tid, NULL, thread_aver
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 很抱歉,我是AI语言模型,无法提供自己的笔记。但是,我可以为您提供一些关于Linux网络编程的信息。Linux网络编程是指在Linux操作系统上进行网络编程的技术,主要包括socket编程、网络协议、网络编程模型等内容。在Linux网络编程中,常用的编程语言有C、C++、Python等。Linux网络编程的应用非常广泛,可以用于开发各种网络应用程序,如Web服务器、邮件服务器、FTP服务器等。同时,Linux网络编程也是网络安全领域的重要技术之一,可以用于网络攻防、数据加密等方面。 ### 回答2: Linux网络编程是一门高级语言编程,包括了网络以及套接字的知识,它的目的是让开发者能够在Linux系统下进行网络应用程序的开发与运行。Linux网络编程中,主要涉及到如下的知识: 1.网络协议:网络协议是数据在计算机网络内传输时所必须遵循的规则和约定。网络协议的共同目标是确保数据的可靠传输。 2.套接字:套接字是一种在网络编程中广泛使用的编程接口,它允许从一个进程向另一个进程通信。通过套接字的编程,可以实现网络上的客户端和服务器端的通信。 3.套接字选项:在套接字编程中,选项提供了一些可选项来控制套接字的行为。例如,可以使用SO_REUSEADDR选项来允许相同的IP地址和端口被多个套接字所使用,或者使用SO_LINGER选项来控制套接字在关闭时的行为。 4.网络编程的主要函数:对于网络编程而言,大多数使用的函数都是socket编程或一些与之相关的函数。如socket、bind、listen、accept、connect、send、recv等。 5.多线程编程和select函数:在网络编程中,常常需要使用多线程编程来同时处理多个套接字,使程序具有高并发性。而select函数可以在一个线程中监听多个套接字的I/O事件,从而优化服务器的性能和响应速度。 6.网络编程的实际应用:网络编程在实际应用中,可以实现许多有趣的功能。例如,可以创建简单的聊天程序、实现网络文件传输、远程控制、实现P2P通信等。 总之,Linux网络编程是一种非常重要的技术,要学习并掌握这门技术,需要掌握网络协议、套接字、多线程编程等基础知识。掌握这些知识后,开发者可以根据实际需求,灵活地使用网络编程技术来实现各种基于网络的应用程序。 ### 回答3: Linux网络编程在现代软件开发中扮演着非常重要的角色,这是因为它是一种跨平台的操作系统,并且为开发人员提供了良好的网络编程接口。以下是一些重要的技术和笔记: 1. 套接字(socket)编程—— 在Linux环境中,套接字是网络编程的关键要素。它被用于实现客户端/服务器应用程序中的通信,例如Web服务器和聊天室应用程序。在编写套接字程序时,必须使用包括bind,listen和accept等操作来处理连接请求。 2. 网络协议—— Linux支持各种网络协议,例如TCP/IP,UDP,ICMP,ARP和RIP等。其中TCP/IP是最常用的网络协议,因为它可靠且易于使用,在开发网络应用程序时需要具备其相关知识,例如TCP连接管理和协议数据包的格式化。 3. 多线程编程—— 在Linux环境中,多线程编程是一种非常重要的技术,可以同时处理多个网络请求,以提高应用程序的性能。通常使用POSIX线程库(pthread)来实现多线程编程,并使用同步和互斥机制来管理线程访问共享变量的冲突。 4. 网络安全—— 网络安全是Linux网络编程的一个重要方面,因为网络应用程序通常需要保护敏感数据和隐私信息。开发人员必须学习诸如SSL和TLS等加密协议,以确保数据传输的安全性。 总结来说,在Linux环境下进行网络编程需要熟悉套接字编程、网络协议、多线程编程和网络安全等技术。这些技术的结合可以实现高效的网络应用程序,并提高用户体验。在掌握这些技术后,开发人员可以将网络编程应用于Web服务器、聊天室应用程序、数据存储器等各种应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值