Technology sharing

Linux multi-processus et multi-stramen(8) Multi-tium

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Multithreading

Post definitionem

Filum exsecutio unitatis in processu est.

Reus ad exsecutionem programmatis in processu currens;

Est saltem unum filum in processu

Plures stamina in processu esse possunt

Fila multiplices omnes facultates eiusdem processus communicant, et singula fila in unificatam schedulationem systematis operantis participat.

Simpliciter accipi potest pro processu = facultates memoriae + filo principale + stamina puerilis +…

Stamina et processuum

Opera enim quae propinqua sunt, multi- lina praeponitur in concursu.

  • Processus: Praecipua unitas subsidii destinatio ab operante ratio.
  • Post: Prima unitas est CPU schedulingarum et mittendi, minima unitas CPU executionis, minima unitas progressionis exsecutionis, et minima unitas progressionis executionis.

Discrimen inter staminum et processuum;

  • memoria spatium
    • Fila multa in processu ejusdem memoriae locum obtinent
    • Plures processus sui iuris habent spatium memoriae
  • Communicatio inter processuum / relatorum
    • Simple communicatio inter relatorum
    • Inter processum communicatio est complexa

Post opibus

  • Shared processus opibus
    • eadem oratio spatio
    • file descriptor mensam
    • Ut quisque signum processionaliter
    • current opus Directory
    • user id quod coetus id
  • Unicum facultates
    • Post acervum
    • Singula stamina privata contexta notitias habent
    • Post id
    • Mandare valorem
    • errno valorem
    • Signum persona verba et scheduling prioritatibus

Post related imperium

Multa mandata sunt ut processus in systemate Linux, pidstat, top, ps, comprehendo, processum spectare possis, etiam inspicere potes.
filo per processum

pidstat imperium

Post sysstat instrumentum debet sub Decuria institui, pidstat sustentari potest.

sudo aptum install sysstat

Optiones

-t: Propono relatorum cum certo processus "

-p: det speciem processus pid

Exemplum

Relatorum videre processus consociata 12345

sudo pidstat -t -p 12345

View relatorum cum omnibus processibus

sudo pidstat -t

Vide stamina cum processu 12345 consociata, output omni 1 secundo

sudo pidstat -t -p 12345 1

Vide stamina cum omnibus processibus consociata, output omne 1 secundo

sudo pidstat t 1

summo imperio

Summo imperio utere ut fila sub quodam processu videas. Opus est ut optio -H in compositione cum -p pid definias.

Optiones

-H: Propono filum informationes

-p: det speciem processus pid

Exemplum

Relatorum videre processus consociata 12345

sudo top -H -p 12345

View relatorum cum omnibus processibus

sudo summo -H *

ps imperium

Utere ps imperio coniuncta cum -T optione ad omnia stamina sub processu

Optiones

-T: Propono filum informationes

-p: det speciem processus pid

Exemplum

Relatorum videre processus consociata 12345

sudo ps -T -p 12345

View relatorum cum omnibus processibus

sudo ps -T

Commune concursus missionum

1. Multi-processus modus

In multi-processus modo, singuli processus diversis officiis responsabiles sunt sine impedimento inter se.

  • Commodum ;
    • Inscriptio spatii processuum independens est.
  • Defectus;
    • Singulis processibus necesse est spatium memoriae sui iuris collocare.
    • Inter-processus collaboratio et communicatio inter-processus magis implicatae sunt
  • Locus applicabilis:
    • Opera multa non valde propinqua sunt, itaque modus processus multimodis adhiberi potest
    • Nullae clientelas inter opera et multi-processus modus adhiberi potest

2. Multi-fila-modus

In multi-relationis modo, fila in processu multiplicari possunt, spatium memoriae communicantes, et sequelae directe communicare possunt.

  • Commodum ;
    • Communicatio inter relatorum simplex est
    • Fila eiusdem processus multiplices facultates communicare possunt et utendo resource amplio.
  • Defectus;
    • Stamina non habent processum electronicum sine spatiis.
    • Filum mutandi et scheduling facultates require.
    • Synchronisatio inter stamina complexa et stamina salutis quaestiones considerandae sunt
  • Locus applicabilis:
    • Sunt clientelae inter opera et multi-plicandi modus adhiberi potest
    • Communicatio inter officia relative frequens et multiplex modus adhiberi potest.

Create filo

1. pthread_create ()

pthread_create() filum creare adhibetur.
Post pthread_create() feliciter vocatur, redibit 0, alioquin errorem codicem reddet.

Munus capitis file:

#include <pthread.h>

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                   void *(*start_routine) (void *), void *arg);
  • 1
  • 2
  • 3
  • 4

Parameter Description:

  • thread: Indicium ad genus pthread_t, filum ID condere solebat.
  • attr: Thread attributum, quod NULL potest esse, significans defectus attributi adhibetur.
  • start_routine: Ingressus functionem sequelae.
  • arg: Parametri ad sequelam ingressum munus transierunt.

valorem reddere:

  • 0: creatus feliciter.
  • EAGAIN: Facultates sufficientes, sequela creatio defecit.
  • EINVAL: parameter invalidus est.
  • ENOMEM: Insufficiens memoria, creatio incassum sequela.

Animadverte:

  • Postquam filius stamen feliciter creatur, independenter ad supplicium accedetur et simul cum aliis stamina exsecuta erit.
  • Bibliotheca -lpthread opus est cum congero.

Exemplum: crea filo

// todo : 创建一个线程,并在线程中打印出“Hello, World!”
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

// 线程函数
//@param arg 线程函数参数
void * print_hello(void *arg) {
    printf("%sn",(char *)arg);
}

int main() {
    pthread_t tid; //? typedef unsigned long int pthread_t;
    // 创建线程
    //@param tid 线程ID
    //@param attr 线程属性
    //@param start_routine 线程函数
    //@param arg 线程函数参数
    int ret = pthread_create(&tid, NULL,print_hello, "Hello, World!");
    if (ret!= 0){
        printf("pthread_create error!n");
        return 1;
    }
    sleep(1); // 等待线程执行完毕
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

2. pthread_exit () exit sequela

pthread_exit() filum exire adhibetur. Postquam filum executionem compleverit, pthread_exit() automatice ad exitum vocabitur.

Munus capitis file:

#include <pthread.h>

void pthread_exit(void *retval);
  • 1
  • 2
  • 3

Parameter Description:

  • retval: Valor rediit cum exit stamina.
  • Postquam munus sequela exsecutum est, pthread_exit() automatice ad exitum vocabitur.

3. pthread_join () observat sequela ad finem

pthread_join() exspectare solebant sequelam ad finem;
Post vocans pthread_join(), filum currente claudetur donec stamen finiatur.

Munus capitis file:

#include <pthread.h>

int pthread_join(pthread_t thread, void **retval);
  • 1
  • 2
  • 3

Parameter Description:

  • thread: Thread ID.
  • retval: Indicium ad sequelam valorem reditus, usus est ad valorem refectum cum stamina exit. (Secundarium indicatorum)

valorem reddere:

  • 0: expecta victoria.
  • EINVAL: parameter invalidus est.
  • ESRCH: Thread ID non est.
  • EDEADLK: Filum in statu deadlock est.

Exemplum:

// todo : 创建一个线程,并在线程中打印出“Hello, World!”
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

// 线程函数
//@param arg 线程函数参数
void * print_hello(void *arg) {
    sleep(1); // 休眠1秒
    printf("%sn",(char *)arg);
    pthread_exit(NULL); // 线程退出
}

int main() {
    pthread_t tid; //? typedef unsigned long int pthread_t;
    // 创建线程
    //* @param tid 线程ID
    //* @param attr 线程属性
    //* @param start_routine 线程函数
    //* @param arg 线程函数参数
    int ret = pthread_create(&tid, NULL,print_hello, "Hello, World!");
    if (ret!= 0){
        printf("pthread_create error!n");
        return 1;
    }

    printf("等待线程结束...n");
    // 等待线程结束
    //* @param thread 线程ID
    //* @param status 线程退出状态
    pthread_join(tid, NULL);

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
等待线程结束...
Hello, World!
  • 1
  • 2

Post separationem

Stamina dividuntur in compositione et delapsu

  • Coniungi possunt
    • Filum combinabile suas facultates repetere potest et ab aliis filis necari;
    • Default status sequelae creatio est coniuncta.
  • separabilis
    • Ab aliis filis REDIVIVUS vel occidi non potest. Facultates sequelae ab systemate cum terminante dimittuntur.
// todo : 创建一个线程,并在线程中打印出“Hello, World!”
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

// 线程函数
//@param arg 线程函数参数
void * print_hello(void *arg) {
    sleep(1); // 休眠1秒
    printf("%sn",(char *)arg);
    pthread_exit(NULL); // 线程退出
}

int main() {
    pthread_t tid; //? typedef unsigned long int pthread_t;
    // 创建线程
    //* @param tid 线程ID
    //* @param attr 线程属性
    //* @param start_routine 线程函数
    //* @param arg 线程函数参数
    int ret = pthread_create(&tid, NULL,print_hello, "Hello, World!");
    if (ret!= 0){
        printf("pthread_create error!n");
        return 1;
    }

    printf("等待线程结束...n");
    // 等待线程结束
    //* @param thread 线程ID
    //* @param status 线程退出状态
    //pthread_join(tid, NULL);//! 阻塞等待线程结束,直到线程结束后才继续往下执行

    //线程分离
    pthread_detach(tid); //! 分离线程,不用等待线程结束后才退出程序,该线程的资源在它终止时由系统来释放。

    printf("主线程结束n");
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

Relatorum plures crea

Exemplum I: crea multa fila praestare diversis operibus

// todo : 创建多个线程,执行不同的任务
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

// 线程函数
//@param arg 线程函数参数
void * print_hello_A(void *arg) {
    sleep(1); // 休眠1秒
    printf("%sn",(char *)arg);
    pthread_exit(NULL); // 线程退出
}
// 线程函数
//@param arg 线程函数参数
void * print_hello_B(void *arg) {
    sleep(2); // 休眠2秒
    printf("%sn",(char *)arg);
    pthread_exit(NULL); // 线程退出
}


int main() {
    pthread_t tidA; //? 存储线程ID  typedef unsigned long int pthread_t;
    pthread_t tidB;
    // 创建线程
    //* @param tid 线程ID
    //* @param attr 线程属性
    //* @param start_routine 线程函数
    //* @param arg 线程函数参数
    int retA = pthread_create(&tidA, NULL,print_hello_A, "A_ Hello, World!");
    if (retA!= 0){
        printf("pthread_create error!n");
        return 1;
    }

    int retB = pthread_create(&tidB, NULL,print_hello_B, "B_ Hello, World!");
    if (retB!= 0){
        printf("pthread_create error!n");
        return 1;
    }
    
    printf("等待线程结束...n");
    // 等待线程结束
    //* @param thread 线程ID
    //* @param status 线程退出状态
    pthread_join(tidA, NULL);//! 阻塞等待线程结束,直到线程结束后才继续往下执行
    pthread_join(tidB, NULL);
    printf("主线程结束n");
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

Exemplum II: crea plura fila ad idem opus faciendum

// todo : 创建多个线程,执行相同任务
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
//? 两个线程执行相同任务,对函数中的值修改了,会不会影响到其他线程的执行?
//! 在多线程编程中,如果多个线程执行相同的任务并且对共享资源进行修改,可能会影响到其他线程的执行。
//! 这是因为多个线程共享相同的内存空间,对共享资源的修改可能会导致竞态条件(race condition),
//! 从而导致不可预测的行为。
//! print_hello函数中的变量i是局部变量,每个线程都会有自己的i副本,因此对i的修改不会影响到其他线程。
//! 但是,如果涉及到共享资源(例如全局变量或静态变量),就需要考虑线程同步的问题,以避免竞态条件。


//*局部变量:每个线程都有自己的栈空间,因此局部变量是线程私有的,不会影响到其他线程。
//*共享资源:如果多个线程访问和修改同一个全局变量或静态变量,就需要使用同步机制(如互斥锁、信号量等)来确保线程安全。
//Linux:在Linux系统中,默认的线程栈大小通常是8MB。可以使用ulimit -s命令查看和修改当前用户的线程栈大小。例如,ulimit -s 1024将线程栈大小设置为1MB。
//Windows:在Windows系统中,默认的线程栈大小是1MB。可以通过编译器选项或在创建线程时指定栈大小来修改。

// 线程函数
//@param arg 线程函数参数
void * print_hello(void *arg) {

    for (char i = 'a'; i < 'z' ; ++i) {
        printf("%cn", i);
        sleep(1); // 休眠1秒
    }
    pthread_exit(NULL); // 线程退出
}

int main() {
    pthread_t tid[2]={0}; //? 存储线程ID的数组  typedef unsigned long int pthread_t;


    for (int i = 0; i < 2; ++i) {
        // 创建线程
        //* @param tid 线程ID
        //* @param attr 线程属性
        //* @param start_routine 线程函数
        //* @param arg 线程函数参数
        int retA = pthread_create(&tid[i], NULL,print_hello, NULL);
        if (retA!= 0){
            printf("pthread_create error!n");
            return 1;
        }
    }

    printf("等待线程结束...n");
    // 等待线程结束
    //* @param thread 线程ID
    //* @param status 线程退出状态
    pthread_join(tid[0], NULL);//! 阻塞等待线程结束,直到线程结束后才继续往下执行
    pthread_join(tid[1], NULL);


    printf("主线程结束n");
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

Communicatio inter relatorum

Alia communicatio inter processuum etiam valet ad communicationem inter fila.

Pelagus filum transit parametri ad puerum stamina

Cum filo partum per functionem pthread_creare() creet, quartus parameter pthread_creatus() est modulus ad functionem pueri fili transiit.

Subthread transit parametri ad principale filum

Cum pueri filum per pthread_exit() munus exeunt, parametros ad filum principale transire potes.

void pth_exit(void *retval);
  • 1

Cum finem sub- liciarum per functionis pthread_join expectans, reditum parametri sub- liciarum obtine.

int pthread_join (pthread_t __th, void **__thread_return);
//二级指针获取到了pthread_exit()函数参数指针的指向地址,通过该地址可以获取到子线程的返回参数。
  • 1
  • 2

Exemplum:

// todo : 线程直接通讯,子线程向父线程传参
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

// 线程函数
//@param arg 线程函数参数
void * print_hello(void *arg) {
    printf("子线程开始,结束之时传递参数100的地址n");

    sleep(1); // 休眠1秒
    //! int num=100;//局部变量,函数结束释放内存
    static int num=100;//* 静态局部变量,函数结束不释放内存,延长生命周期
    pthread_exit(&num); // 线程退出
}



int main() {
    pthread_t tid; //? 存储线程ID  typedef unsigned long int pthread_t;
    // 创建线程
    //* @param tid 线程ID
    //* @param attr 线程属性
    //* @param start_routine 线程函数
    //* @param arg 线程函数参数
    int retA = pthread_create(&tid, NULL,print_hello, NULL);
    if (retA!= 0){
        printf("pthread_create error!n");
        return 1;
    }



    printf("等待线程结束...n");
    void* num;//获取子进程传递的参数,num指向了子进程传递的参数
    // 等待线程结束
    //* @param thread 线程ID
    //* @param status 线程退出状态
    pthread_join(tid, (void **)&num);//! 阻塞等待线程结束,直到线程结束后才继续往下执行
    printf("子线程结束,传递的参数为%dn",*(int*)num);
    printf("主线程结束n");
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

Post mutex

Post mutex

Mutex synchronisatio est mechanismus usus ad refrenandum accessum ad facultates communes.

Praecipua utilitas sequelarum est facultas informationes communicandi per variabiles globales, sed haec convenientia communicatio cum pretio venit:

Providendum est ut plures stamina eadem variabilia eodem tempore non mitigentur

Filum variabiles ab aliis stamina mutatis non leget. Re vera duo stamina simul sectionem criticam accedere non possunt.

Principium cincinno mutex

Principium cincinnis mutex est quod cum linum intra aream mutex conatur, si area mutex ab aliis stamina iam occupata est, stamina obstruetur donec area mutex dimittatur.

Est essentialiter variabilis speciei pthread_mutex_t, quae integrum valorem continet ad statum regionis mutex exprimendum.
Cum valor 1, significat quod subsidia critica hodiernae pro accessu certare possunt, et filum quod mutex cincinno obtinet sectionem criticam ingredi potest. Hoc tempore valor 0 est et alia sequela tantum expectare possunt.
Cum valor 0 est, significat praesens criticum subsidium ab aliis sequelis occupari neque sectionem criticam ingredi ac tantum expectare posse.

Characteres mutex cincinni

typedef union
{
  struct __pthread_mutex_s __data; // 互斥锁的结构体
  char __size[__SIZEOF_PTHREAD_MUTEX_T];// 互斥锁的大小
  long int __align;// 互斥锁的对齐
} pthread_mutex_t;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • Sera mutex est genus pthread_mutex_t variabile, quod seram mutex repraesentat.
  • Si duo stamina ad eandem pthread_mutex_t variabilem accesserint, tunc ad eandem seram mutex accedunt
  • Variabiles correspondentes definiuntur in pthreadtypes.h capitis fasciculi, quod est corpus commune continens structuram.

Utere mutex cincinni

Duae viae principales sunt ad initialize stamina mutex comas;

static initialization

  • Definire variabilem typo pthread_mutex_t et initialize eam ad PTHREAD_MUTEX_INITIALIZER.
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER
  • 1

dynamic initialization

Dynamic initialization Dynamic initialization duo munera maxime involvit: munus pthread_mutex_init et munus pthread_mutex_destroy

pthread_mutex_init () function

Mutex seram initialize usus, duos parametros accipit: oratio mutex seram et attributa cincinnis mutex.

Munus capitis file:

#include <pthread.h>

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
  • 1
  • 2
  • 3

Parameter Description:

  • Mutex: Indicium ad genus pthread_mutex_t, inscriptione mutex cincinno reponenda.
  • attr: attributum cincinno mutex, quod esse NULL potest, significans attributum defectui adhibitum.

valorem reddere:

  • 0: felix Initialization.
  • Error in defectu codice redditur.
pthread_mutex_destroy () function

Mutex seram destruens usus est, modulum unum accipit: cincinni mutex oratio.

Munus capitis file:

#include <pthread.h>

int pthread_mutex_destroy(pthread_mutex_t *mutex);
  • 1
  • 2
  • 3

Parameter Description:

  • Mutex: Indicium ad genus pthread_mutex_t, inscriptione mutex cincinno reponenda.

valorem reddere:

  • 0: felix interitus.
  • Error in defectu codice redditur.

Exemplum:

// todo :  互斥锁;创建两个线程,分别对全局变量进⾏ +1 操作
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>


static int global = 0;// 全局变量

//静态初始化互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;// 互斥锁
//动态初始化互斥锁
pthread_mutex_t mut;// 互斥锁

// 线程函数
//@param arg 线程函数参数
void * print_hello(void *arg) {
    printf("子线程开始n");

    int loops = *(int *)arg;
    int i,tmp = 0;
    for (i = 0;i < loops;i++){
        pthread_mutex_lock(&mut);// 加锁
        printf("子线程%d,global=%dn",i,global);
        tmp = global;
        tmp++;
        global = tmp;
        pthread_mutex_unlock(&mut);// 解锁
    }
    printf("子线程结束n");
    pthread_exit(NULL); // 线程退出
}



int main() {

    // 动态初始化互斥锁
    //* @param mutex 互斥锁
    //* @param attr 互斥锁属性 NULL 是默认属性
    int r= pthread_mutex_init(&mut,NULL);
    if (r!= 0){
        printf("pthread_mutex_init error!n");
        return 1;
    }

    pthread_t tid[2]={0}; //? 存储线程ID  typedef unsigned long int pthread_t;
    int arg=20;
    for (int i = 0; i < 2; i++){
        // 创建线程
        //* @param tid 线程ID
        //* @param attr 线程属性
        //* @param start_routine 线程函数
        //* @param arg 线程函数参数
        int retA = pthread_create(&tid[i], NULL,print_hello, &arg);
        if (retA!= 0){
            printf("pthread_create error!n");
            return 1;
        }
    }




    printf("等待线程结束...n");
    // 等待线程结束
    //* @param thread 线程ID
    //* @param status 线程退出状态
    pthread_join(tid[0],NULL );//! 阻塞等待线程结束,直到线程结束后才继续往下执行
    pthread_join(tid[1],NULL );

    printf("%dn",global);
    printf("主线程结束n");

    // 销毁动态创建的互斥锁
    //* @param mutex 互斥锁
    pthread_mutex_destroy(&mut);// 销毁互斥锁

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79

Post synchronisation

Re: synchronisation: significat ordinem facultatum accessum per visitatores per alias machinas ex mutua exclusione (in pluribus).

Conditio variabilis: Mechanismus provisus per sequelam bibliothecam speciatim pro filo synchronisationi.

Typical applicatio missionis pro filo synchronisation est inter effectrix et consumers.

Producentis et emptoris quaestiones

In hoc exemplari dividitur in sequelam producentis et filum consumptorium, et processus synchronisationum plurium staminum per hoc filum simulatur.

In hoc exemplari, sequentia membra requiruntur:

  • CELLA: usus est copia products, plerumque ut resource participatur
  • Producentis filum: ad producendum products
  • Consumer filum: usus products ad perussi

principium;

Cum nulla sit amet in pellentesque, dolor eget eget elit donec sit amet ante ipsum.

Cum horreis products impletur, operante filum expectandum eget donec dolor stamina producta consumat.

Exemplum exsequendi effectoris et consumendi exempla ex mutex cincinni

Pelagus filum est dolor

n sub relatorum ut effectrix

// todo :  基于互斥锁实现⽣产者与消费者模型主线程为消费者,n 个⼦线程作为⽣产者
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
static int n = 0; // 产品数量
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;// 互斥锁

//生产者执行函数
void * dofunc(void *arg) {
    int arg1 = *(int*)arg;
    for (int i = 0; i <arg1; i++) {
        //获取互斥锁
        pthread_mutex_lock(&mutex);
        //生产产品
        printf("生产者%ld生产了%d个产品n",pthread_self(),++n);//! pthread_self()返回当前线程ID
        //释放互斥锁
        pthread_mutex_unlock(&mutex);
        //休眠1秒
        sleep(1);
    }
    pthread_exit(NULL);
}


int main() {
    pthread_t tid[4]={0}; //? 存储线程ID  typedef unsigned long int pthread_t;
    int arr[4]={1,2,3,4};
    for (int i = 0; i < 4; i++) {
        // 创建线程
        //* @param tid 线程ID
        //* @param attr 线程属性
        //* @param start_routine 线程函数
        //* @param arg 线程函数参数
        int retA = pthread_create(&tid[i], NULL,dofunc,&arr[i] );
        if (retA!= 0){
            printf("pthread_create error!n");
            return 1;
        }
    }
    //消费者执行

    for (int i = 0;i<10;i++) {
        //获取互斥锁
        pthread_mutex_lock(&mutex);
        while (n > 0){
            //消费产品
            printf("消费者%ld消费了1个产品:%dn",pthread_self(),n--);
        }
        //释放互斥锁
        pthread_mutex_unlock(&mutex);
        //休眠1秒
        sleep(1);
    }


    printf("等待线程结束...n");
    // 等待线程结束
    //* @param thread 线程ID
    //* @param status 线程退出状态
    pthread_join(tid[0],NULL );//! 阻塞等待线程结束,直到线程结束后才继续往下执行
    pthread_join(tid[1],NULL );
    pthread_join(tid[2],NULL );
    pthread_join(tid[3],NULL );

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

conditio variabilis

Conditio variabilis est mechanismum synchronismum quae filo exspectare sinit certam condicionem occurrere antequam currere perseveret.

Principium conditionis variabilis est quod mutex seram et queue exspectantem continet.

Serae Mutex usus sunt ad queues expectantes et variabiles conditiones tuendas.

Insert imaginem descriptionis hic

Conditio variabilis initialization

Quale conditionis variabilis est, genus pthread_cond_t

其他线程可以阻塞在这个条件变量上, 或者唤
醒阻塞在这个条件变量上的线程
typedef union
{
  struct __pthread_cond_s __data;
  char __size[__SIZEOF_PTHREAD_COND_T];
  __extension__ long long int __align;
} pthread_cond_t;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Initialization variarum condicionis in initializationem statam et initializationem dynamicam dividitur.

static initialization

Ad statum variabilium stabiliter initialized, debes primum variam figurae pthread_cond_t definire, et deinde initialem eam ad PTHREAD_COND_INITALIZER definire.

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  • 1

Dynamic initialization pthread_cond_init ()

Ut condicionem variabilem dynamice initializem, debes primum variabilem speciei pthread_cond_t definire, deinde munus pthread_cond_init vocare ad initialem efficere.

Munus capitis file:

#include <pthread.h>

int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
  • 1
  • 2
  • 3

Parameter Description:

  • cond: Indicium ad genus pthread_cond_t, inscriptionis condicionis variabilis reponendarum usus est.
  • attr: attributum condicionis variabilis, quae nullo attributo defectu uti potest.

valorem reddere:

  • 0: felix Initialization.
  • Error in defectu codice redditur.

pthread_cond_destroy ()

Conditio variabilium destruenda adhibita, modulum unum accipit: oratio condicionis variabilis.

Munus capitis file:

#include <pthread.h>

int pthread_cond_destroy(pthread_cond_t *cond);
  • 1
  • 2
  • 3

Parameter Description:

  • cond: Indicium ad genus pthread_cond_t, inscriptionis condicionis variabilis reponendarum usus est.

valorem reddere:

  • 0: felix interitus.
  • Error in defectu codice redditur.

Usus conditionis variabiles

Usus variabilium condicionis in exspectationem et notificationem dividitur

Exspecta pthread_cond_wait()

Munus exspectans pthread_cond_wait() tres parametri accipit: oratio condicionis variabilis, oratio mutex cincinno, tempus exspectans.

Munus capitis file:

#include <pthread.h>

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
  • 1
  • 2
  • 3

Parameter Description:

  • cond: Indicium ad genus pthread_cond_t, inscriptionis condicionis variabilis reponendarum usus est.
  • Mutex: Indicium ad genus pthread_mutex_t, inscriptione mutex cincinno reponenda.
  • abstime: timeout, quod potest esse NULL, significans non timeout.

valorem reddere:

  • 0: expecta victoria.
  • Error in defectu codice redditur.

Certiorem pthread_cond_signal ()

notitia munus
pthread_cond_signal() unum modulum accipit: oratio condicionis variabilis.

Munus capitis file:

#include <pthread.h>

int pthread_cond_signal(pthread_cond_t *cond);
  • 1
  • 2
  • 3

Parameter Description:

  • cond: Indicium ad genus pthread_cond_t, inscriptionis condicionis variabilis reponendarum usus est.

valorem reddere:

  • 0: Notification felix.
  • Error in defectu codice redditur.

Certiorem omnia pthread_cond_broadcast ()

Certiorem omnia munera
pthread_cond_broadcast() unum modulum accipit: oratio condicionis variabilis.

Munus capitis file:

#include <pthread.h>

int pthread_cond_broadcast(pthread_cond_t *cond);
  • 1
  • 2
  • 3

Parameter Description:

  • cond: Indicium ad genus pthread_cond_t, inscriptionis condicionis variabilis reponendarum usus est.

valorem reddere:

  • 0: Notification felix.
  • Error in defectu codice redditur.

Exemplum effectum producentis et consumptoris exemplorum secundum variabilium conditionalium

Insert imaginem descriptionis hic

step 1 : 消费者线程判断消费条件是否满足 (仓库是否有产品),如果有产品可以消费,则可以正
常消费产品,然后解锁
step 2 : 当条件不能满足时 (仓库产品数量为 0),则调用 pthread_cond_wait 函数, 这个函数
            具体做的事情如下:
            在线程睡眠之前,对互斥锁解锁
            让线程进⼊到睡眠状态
            等待条件变量收到信号时 唤醒,该函数重新竞争锁,并获取锁后,函数返回 
step 3 :重新判断条件是否满足, 如果不满足,则继续调用 pthread_cond_wait 函数
step 4 : 唤醒后,从 pthread_cond_wait 返回,消费条件满足,则正常消费产品
step 5 : 释放锁,整个过程结束
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Cur variabiles conditiones cum mutex crinibus adhibendae sunt?

Communis notitia protegat:

Serae Mutex ad communes notitias tuendas adhibentur et ut una tantum fila accedere ac mutare possit notitias simul.

Haec notitias gentes et repugnantia vitat.

Conditiones variabiles pro communicatione inter stamina adhibentur ut alia fila certiorem faciant condicionem quandam occurrere.

Attamen operatio variabilium conditionum ipsa tutelam notitiarum communium non praebet et ideo cum pessulo mutex adhibendus est.

Falsum fuge-sursum:

Una notio variabilium conditionum est ut spuria evigilatio contingat.

Hoc est, sequela excitatur sine notificatione expressa. Ad vitandum operationes falsas hoc modo causantur;

Reprehendo sequela opus est utrum condicio reapse convenerit post evigilationem.

Mutex usus efficit ut notitia communis communicata ab aliis sequelis condiciones reprimendo non modificatur, ita errores evitandos evigilationibus spuriis causantibus.

Vide notificatio recta;

Cum linum alia stamina per variabiles condiciones notificat, necesse est ut data communia renovata sit antequam certiores fiant.

Mutex hoc praestat ut omnes operationes renovationis notitiae ante seram solvendas expleverint.

Item, filum recipiens notificationem debet habere mutex antequam condicionem inprimat, ut notitia stabilis sit cum condicio inhibetur.

Exsequendi synchronisation composita exemplaria:
Mutex crines cum conditione variabilium coniungendo possunt exemplaria synchronisationi implicatissima efficere, ut problemata effectrix dolor, problemata lector-scriptor, etc. Mutexes datas communes tuentur, et variabiles condiciones adhibentur ad coordinationem et communicationem inter stamina.

// todo :  条件变量
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdlib.h>


static int number = 0;// 产品数量
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;// 互斥锁
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;// 条件变量

// 线程函数
//@param arg 线程函数参数
void * thread_handler(void *arg) {
    int cnt = atoi((char *)arg);// 获取线程参数
    int i,tmp;// 临时变量
    for(i = 0;i < cnt;i++){// 生产产品
        pthread_mutex_lock(&mtx);// 上锁
        printf("线程 [%ld] ⽣产⼀个产品,产品数量为:%dn",pthread_self(),++number);
        pthread_mutex_unlock(&mtx);// 解锁

        //! 唤醒cond阻塞的线程
        //! @param cond 条件变量
        //pthread_cond_signal(&cond);//! 只能唤醒一个线程,如果有多个线程在等待,则只有一个线程会被唤醒
        //唤醒所有线程
        pthread_cond_broadcast(&cond);
    }
    pthread_exit((void *)0);// 线程退出
}



int main(int argc,char *argv[]) {

    pthread_t tid[argc-1];// 线程ID
    int i;
    int err;
    int total_of_produce = 0;// 总共生产的产品数量
    int total_of_consume = 0;// 总共消费的产品数量
    bool done = false;// 是否完成生产
    //循环创建线程
    for (i = 1;i < argc;i++){
        total_of_produce += atoi(argv[i]);// 计算总共需要生产的产品数量
        // 创建线程
        err = pthread_create(&tid[i-1],NULL,thread_handler,(void *)argv[i]);
        if (err != 0){
            perror("[ERROR] pthread_create(): ");
            exit(EXIT_FAILURE);
        }
    }
    //消费者
    for (;;){
        //*先获取锁,再进行条件变量的等待
        pthread_mutex_lock(&mtx);// 上锁

        //*while循环来判断条件,避免虚假唤醒
        while(number == 0) {// 等待生产者生产产品
            //! 等待条件变量
            //! @param cond 条件变量
            //! @param mtx 互斥锁
            //! 函数中会释放互斥锁,并阻塞线程,
            //! 直到条件变量被唤醒,再重新竞争互斥锁,获取互斥锁并继续执行
            pthread_cond_wait(&cond, &mtx);
        }
        while(number > 0){
            total_of_consume++;// 总共消费的产品数量
            printf("消费⼀个产品,产品数量为:%dn",--number);// 消费产品
            done = total_of_consume >= total_of_produce;// 是否完成生产
        }
        pthread_mutex_unlock(&mtx);// 解锁

        if (done)// 是否完成生产
            break;
    }

    // 等待线程退出
    for(i = 0;i < argc-1;i++){
        pthread_join(tid[i],NULL);
    }

    return 0;

}
    //循环创建线程
    for (i = 1;i < argc;i++){
        total_of_produce += atoi(argv[i]);// 计算总共需要生产的产品数量
        // 创建线程
        err = pthread_create(&tid[i-1],NULL,thread_handler,(void *)argv[i]);
        if (err != 0){
            perror("[ERROR] pthread_create(): ");
            exit(EXIT_FAILURE);
        }
    }
    //消费者
    for (;;){
        //*先获取锁,再进行条件变量的等待
        pthread_mutex_lock(&mtx);// 上锁

        //*while循环来判断条件,避免虚假唤醒
        while(number == 0) {// 等待生产者生产产品
            //! 等待条件变量
            //! @param cond 条件变量
            //! @param mtx 互斥锁
            //! 函数中会释放互斥锁,并阻塞线程,
            //! 直到条件变量被唤醒,再重新竞争互斥锁,获取互斥锁并继续执行
            pthread_cond_wait(&cond, &mtx);
        }
        while(number > 0){
            total_of_consume++;// 总共消费的产品数量
            printf("消费⼀个产品,产品数量为:%dn",--number);// 消费产品
            done = total_of_consume >= total_of_produce;// 是否完成生产
        }
        pthread_mutex_unlock(&mtx);// 解锁

        if (done)// 是否完成生产
            break;
    }

    // 等待线程退出
    for(i = 0;i < argc-1;i++){
        pthread_join(tid[i],NULL);
    }

    return 0;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127