प्रौद्योगिकी साझेदारी

लिनक्स बहु-प्रक्रिया बहु-थ्रेडिंग् च (8) बहु-थ्रेडिंग्

2024-07-12

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

बहुसूत्रीकरणम्

सूत्रपरिभाषा

सूत्रं प्रक्रियायां निष्पादन-एककं भवति ।

वर्तमानप्रक्रियायां कार्यक्रमानां निष्पादनस्य उत्तरदायी,

एकस्मिन् प्रक्रियायां न्यूनातिन्यूनम् एकः सूत्रः भवति

एकस्मिन् प्रक्रियायां बहुविधसूत्राणि भवितुम् अर्हन्ति

अनेकाः सूत्राः एकस्यामेव प्रक्रियायाः सर्वाणि संसाधनानि साझां कुर्वन्ति, प्रत्येकं सूत्रं च प्रचालनतन्त्रस्य एकीकृतनिर्धारणे भागं गृह्णाति

इदं केवलं प्रक्रिया = स्मृतिसंसाधनम् + मुख्यसूत्रम् + बालसूत्रम् +... इति अवगन्तुं शक्यते।

सूत्राणि प्रक्रियाश्च

निकटसम्बद्धानां कार्याणां कृते समवर्तीकाले बहुसूत्रीकरणं प्राधान्यं भवति येषु कार्येषु निकटसम्बन्धः नास्ति तथा च तुल्यकालिकरूपेण स्वतन्त्रः भवति, तेषां कृते बहुप्रक्रियायाः चयनं अनुशंसितम्

  • प्रक्रिया : प्रचालनप्रणाल्याः संसाधनविनियोगस्य मूलभूतं एककं संसाधनविनियोगस्य लघुतमं एककं, कार्यक्रमस्य निष्पादन-निर्धारण-एककं, कार्यक्रमस्य च चलन-दृष्टान्तः च अस्ति ।
  • थ्रेड् : इदं CPU समयनिर्धारणस्य प्रेषणस्य च मूलभूतं एककं, CPU निष्पादनस्य लघुतमं एककं, कार्यक्रमनिष्पादनप्रवाहस्य लघुतमं एककं, कार्यक्रमनिष्पादनस्य लघुतमं एककं च अस्ति

सूत्राणां प्रक्रियाणां च भेदः : १.

  • स्मृतिस्थानम्
    • प्रक्रियायां बहुविधाः सूत्राः समानस्मृतिस्थानं साझां कुर्वन्ति
    • बहुविधप्रक्रियासु स्वतन्त्रस्मृतिस्थानं भवति
  • प्रक्रियाणां/सूत्राणां मध्ये संचारः
    • सूत्राणां मध्ये सरलः संचारः
    • अन्तरप्रक्रियासञ्चारः जटिलः अस्ति

सूत्रसंसाधनम्

  • साझा प्रक्रिया संसाधन
    • समानं पतास्थानं
    • सञ्चिकावर्णकसारणी
    • प्रत्येकं संकेतं कथं संसाधितं भवति
    • वर्तमान कार्यनिर्देशिका
    • user id तथा group id
  • अद्वितीय संसाधन
    • सूत्रस्य ढेरः
    • प्रत्येकं सूत्रे निजीसन्दर्भसूचना भवति
    • सूत्र id
    • रजिस्टर मूल्य
    • एर्र्नो मूल्यम्
    • संकेतमास्कशब्दाः समयनिर्धारणप्राथमिकता च

सूत्रसम्बद्धाः आदेशाः

Linux प्रणाल्यां प्रक्रियां द्रष्टुं बहवः आदेशाः सन्ति, यथा pidstat, top, ps, प्रक्रियां द्रष्टुं शक्नुवन्ति, a अपि द्रष्टुं शक्नुवन्ति
प्रक्रियायाः अन्तर्गतं सूत्रम्

pidstat आदेशः

ubuntu इत्यस्य अधः sysstat tool इत्यस्य संस्थापनस्य आवश्यकतायाः अनन्तरं pidstat इत्यस्य समर्थनं कर्तुं शक्यते ।

sudo apt sysstat संस्थापयन्तु

विकल्पाः

-t: निर्दिष्टप्रक्रियायाः सह सम्बद्धानि सूत्राणि प्रदर्शयन्तु

-p: प्रक्रिया pid निर्दिशतु

उदाहरण

प्रक्रिया 12345 इत्यनेन सह सम्बद्धानि सूत्राणि पश्यन्तु

सुदो पिडस्तत् -त -प 12345

सर्वैः प्रक्रियाभिः सह सम्बद्धानि सूत्राणि पश्यन्तु

सुदो पिदस्तत् -त

प्रक्रिया 12345 इत्यनेन सह सम्बद्धानि धागानि पश्यन्तु, प्रत्येकं 1 सेकण्ड् मध्ये आउटपुट्

सुदो पिडस्तत् -त -प 12345 1

सर्वैः प्रक्रियाभिः सह सम्बद्धानि सूत्राणि पश्यन्तु, प्रत्येकं १ सेकेण्ड् मध्ये आउटपुट् कुर्वन्तु

सुदो पिदस्तत् -t 1

top आदेशः

कस्यचित् प्रक्रियायाः अन्तर्गतं थ्रेड् द्रष्टुं top आदेशस्य उपयोगं कुर्वन्तु pid निर्दिष्टुं -p इत्यनेन सह संयोजनेन -H विकल्पस्य उपयोगः करणीयः ।

विकल्पाः

-H: सूत्रसूचना प्रदर्शयन्तु

-p: प्रक्रिया pid निर्दिशतु

उदाहरण

प्रक्रिया 12345 इत्यनेन सह सम्बद्धानि सूत्राणि पश्यन्तु

सुदो शीर्ष -H -p 12345

सर्वैः प्रक्रियाभिः सह सम्बद्धानि सूत्राणि पश्यन्तु

सुदो शीर्ष -H

ps आदेशः

प्रक्रियायाः अन्तर्गतं सर्वान् थ्रेड् द्रष्टुं -T विकल्पेन सह संयुक्तं ps आदेशस्य उपयोगं कुर्वन्तु

विकल्पाः

-T: सूत्रसूचना प्रदर्शयन्तु

-p: प्रक्रिया pid निर्दिशतु

उदाहरण

प्रक्रिया 12345 इत्यनेन सह सम्बद्धानि सूत्राणि पश्यन्तु

सुदो प्स -त -प 12345

सर्वैः प्रक्रियाभिः सह सम्बद्धानि सूत्राणि पश्यन्तु

सुदो प्स -T

सामान्य समवर्ती परिदृश्य

1. बहुप्रक्रियाविधिः

बहुप्रक्रियाविधाने प्रत्येकं प्रक्रिया परस्परं बाधां विना भिन्नानां कार्याणां उत्तरदायी भवति ।

  • लाभ:
    • प्रक्रियायाः पतास्थानं स्वतन्त्रं भवति एकदा प्रक्रियायां अपवादः जातः चेत् अन्यप्रक्रियासु प्रभावं न करिष्यति ।
  • अभावः : १.
    • प्रत्येकं प्रक्रियायां स्वतन्त्रस्मृतिस्थानं आवंटयितुं आवश्यकं भवति प्रक्रियायाः निर्माणं महत् भवति तथा च अधिका स्मृतिः गृह्णाति ।
    • अन्तरप्रक्रियासहकार्यं अन्तरप्रक्रियासञ्चारं च अधिकं जटिलं भवति
  • प्रयोज्यदृश्यम् : १.
    • बहुविधकार्यं बहु निकटतया सम्बद्धं नास्ति, अतः बहुप्रक्रियाविधिः उपयोक्तुं शक्यते
    • कार्याणां मध्ये आश्रयाः नास्ति बहुप्रक्रियाविधिः च उपयोक्तुं शक्यते

2. बहुसूत्रयुक्तविधिः

बहु-सूत्र-विधाने प्रक्रियायां बहु-सूत्राणि भवितुम् अर्हन्ति, समान-स्मृति-स्थानं साझां कुर्वन्ति, सूत्राणि च प्रत्यक्षतया संवादं कर्तुं शक्नुवन्ति ।

  • लाभ:
    • सूत्राणां मध्ये संचारः सरलः अस्ति
    • एकस्यामेव प्रक्रियायाः बहुविधाः सूत्राः संसाधनानाम् साझेदारी कर्तुं संसाधनानाम् उपयोगे सुधारं कर्तुं च शक्नुवन्ति ।
  • अभावः : १.
    • मुख्यसूत्रस्य निर्गमनानन्तरं अन्ये सूत्राणि अपि निर्गमिष्यन्ति ।
    • थ्रेड् स्विचिंग् तथा शेड्यूलिंग् इत्येतयोः कृते संसाधनानाम् आवश्यकता भवति ।
    • सूत्राणां मध्ये समन्वयनं जटिलं भवति तथा च सूत्रसुरक्षाविषयेषु विचारः करणीयः
  • प्रयोज्यदृश्यम् : १.
    • कार्याणां मध्ये आश्रयाः सन्ति बहु-थ्रेडिंग् मोड् इत्यस्य उपयोगः कर्तुं शक्यते
    • कार्याणां मध्ये संचारः तुल्यकालिकरूपेण बहुधा भवति तथा च बहु-सूत्रविधानस्य उपयोगः कर्तुं शक्यते ।

सूत्रं रचयतु

1. pthread_create () 1.1.

pthread_create() इत्यस्य उपयोगः थ्रेड् निर्मातुं भवति ।
pthread_create() इत्यस्य सफलतया आह्वानानन्तरं 0 प्रत्यागमिष्यति, अन्यथा त्रुटिसङ्केतं प्रत्यागमिष्यति ।

कार्यशीर्षकसञ्चिका : १.

#include <pthread.h>

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

पैरामीटर् विवरणम् : १.

  • thread: pthread_t प्रकारस्य सूचकः, थ्रेड् ID संग्रहणार्थं उपयुज्यते ।
  • attr: थ्रेड् एट्रिब्यूट्, यत् NULL भवितुम् अर्हति, पूर्वनिर्धारितं एट्रिब्यूट् उपयुज्यते इति सूचयति ।
  • start_routine: थ्रेड् इत्यस्य प्रविष्टिकार्यम्।
  • arg: थ्रेड् प्रविष्टि कार्याय पारितानि पैरामीटर्।

return value: 1.1.

  • 0: सफलतया निर्मितम्।
  • EAGAIN: अपर्याप्ताः संसाधनाः, सूत्रनिर्माणं विफलम्।
  • EINVAL: पैरामीटर् अमान्यम् अस्ति।
  • ENOMEM: अपर्याप्तस्मृतिः, सूत्रनिर्माणं विफलम्।

सूचना:

  • एकदा बालसूत्रं सफलतया निर्मितं जातं चेत्, तस्य निष्पादनार्थं स्वतन्त्रतया निर्धारितं भविष्यति, अन्यैः सूत्रैः सह समवर्ती निष्पादनं च भविष्यति ।
  • संकलनकाले -lpthread पुस्तकालयस्य लिङ्क् करणीयम् ।

उदाहरणम् : सूत्रं रचयन्तु

// 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() सूत्रात् निर्गच्छति

pthread_exit() इत्यस्य उपयोगः थ्रेड् इत्यस्मात् निर्गन्तुं भवति ।

कार्यशीर्षकसञ्चिका : १.

#include <pthread.h>

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

पैरामीटर् विवरणम् : १.

  • retval: सूत्रस्य निर्गमनसमये प्रत्यागतं मूल्यम् ।
  • थ्रेड् फंक्शन् निष्पादितस्य अनन्तरं pthread_exit() स्वयमेव निर्गन्तुं आह्वयते ।

3. pthread_join() सूत्रस्य समाप्तिम् प्रतीक्षते

pthread_join() इत्यस्य उपयोगः थ्रेड् समाप्तिं प्रतीक्षितुं भवति,
pthread_join() इति आह्वानं कृत्वा, वर्तमानं थ्रेड् यावत् थ्रेड् समाप्तं न भवति तावत् अवरुद्धं भविष्यति ।

कार्यशीर्षकसञ्चिका : १.

#include <pthread.h>

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

पैरामीटर् विवरणम् : १.

  • thread: धागा ID।
  • retval: थ्रेड् रिटर्न् वैल्यू इत्यस्य सूचकः, थ्रेड् निर्गमनसमये प्रत्यागतं मूल्यं संग्रहीतुं उपयुज्यते । (द्वितीयक सूचकः) २.

return value: 1.1.

  • 0: सफलतायाः प्रतीक्षां कुर्वन्तु।
  • EINVAL: पैरामीटर् अमान्यम् अस्ति।
  • ESRCH: थ्रेड् आईडी नास्ति।
  • EDEADLK: सूत्रं गतिरोधस्थितौ अस्ति।

उदाहरण:

// 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

सूत्रविच्छेदः

सूत्राणि संयोजनीयानि विच्छेदनीयानि च इति विभक्ताः भवन्ति

  • संयोजितुं शक्यते
    • संयोजनीयः सूत्रः स्वस्य संसाधनं पुनः प्राप्तुं शक्नोति, अन्यैः सूत्रैः च मारितुं शक्नोति, यावत् अन्यैः सूत्रैः पुनः न प्राप्यते तावत् तस्य स्मृतिसम्पदः (स्टैक इत्यादिः) न मुक्ताः भवन्ति
    • थ्रेड् निर्माणस्य पूर्वनिर्धारितस्थितिः संयोजनीयः अस्ति ।
  • विच्छेद्यम्
    • अन्यैः सूत्रैः पुनः प्रयोक्तुं वा मारयितुं वा न शक्यते सूत्रस्य संसाधनं यदा समाप्तं भवति तदा प्रणाल्याः मुक्ताः भवन्ति ।
// 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

अनेकसूत्राणि रचयन्तु

उदाहरणम् 1: भिन्नानि कार्याणि कर्तुं बहुविधाः थ्रेड् रचयन्तु

// 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

उदाहरणम् 2: एकमेव कार्यं कर्तुं बहुविधं थ्रेड् रचयन्तु

// 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

सूत्राणां मध्ये संचारः

प्रक्रियाणां मध्ये अन्यः संचारः सूत्राणां मध्ये संचारस्य अपि प्रवर्तते ।

मुख्यसूत्रः बालसूत्रं प्रति पैरामीटर्स् पारयति

pthread_create() फंक्शन् इत्यस्य माध्यमेन चाइल्ड् थ्रेड् रचयन्ते सति, pthread_create() इत्यस्य चतुर्थः पैरामीटर् बाल थ्रेड् इत्यस्य फंक्शन् इत्यस्मै पारितः पैरामीटर् भवति ।

उपधागः मुख्यसूत्रं प्रति पैरामीटर्स् पारयति

pthread_exit() फंक्शन् मार्गेण बालसूत्रात् निर्गच्छन्ति चेत्, भवान् मुख्यसूत्रे पैरामीटर्स् पारयितुं शक्नोति ।

void pth_exit(void *retval);
  • 1

pthread_join() फंक्शन् इत्यस्य माध्यमेन उप-थ्रेड् इत्यस्य अन्तं प्रतीक्षमाणे उप-थ्रेड् इत्यस्य रिटर्न् पैरामीटर्स् प्राप्नुवन्तु ।

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

उदाहरण:

// 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

सूत्र म्यूटेक्स

सूत्र म्यूटेक्स

Mutex इति समन्वयनतन्त्रं यस्य उपयोगः साझासंसाधनानाम् अभिगमनं नियन्त्रयितुं भवति ।

थ्रेड् इत्यस्य मुख्यं लाभं वैश्विकचरद्वारा सूचनां साझां कर्तुं क्षमता अस्ति, परन्तु एतत् सुविधाजनकं साझेदारी मूल्येन आगच्छति:

अनेकाः सूत्राः एकस्मिन् समये एकमेव चरं न परिवर्तयन्ति इति सुनिश्चितं कर्तव्यम्

अन्यैः सूत्रैः परिवर्तिताः चराः सूत्रं न पठति वस्तुतः द्वौ सूत्रौ एकस्मिन् समये महत्त्वपूर्णविभागं प्राप्तुं न शक्नुवन्ति ।

म्यूटेक्स लॉक इत्यस्य सिद्धान्तः

म्यूटेक्स-लॉक् इत्यस्य सिद्धान्तः अस्ति यत् यदा कश्चन थ्रेड् म्यूटेक्स् क्षेत्रे प्रवेशं कर्तुं प्रयतते तदा यदि म्यूटेक्स् क्षेत्रं पूर्वमेव अन्यैः थ्रेड् इत्यनेन आक्रान्तः अस्ति तर्हि म्यूटेक्स् क्षेत्रं मुक्तं न भवति तावत् थ्रेड् अवरुद्धः भविष्यति

इदं मूलतः pthread_mutex_t प्रकारस्य चरः अस्ति, यस्मिन् mutex क्षेत्रस्य स्थितिं प्रतिनिधितुं पूर्णाङ्कमूल्यं भवति ।
यदा मूल्यं 1 भवति तदा तस्य अर्थः अस्ति यत् वर्तमानः महत्त्वपूर्णः संसाधनः अभिगमनार्थं स्पर्धां कर्तुं शक्नोति, तथा च यः सूत्रः म्यूटेक्स् तालं प्राप्नोति सः महत्त्वपूर्णविभागे प्रवेशं कर्तुं शक्नोति । अस्मिन् समये मूल्यं 0 अस्ति अन्ये सूत्राणि केवलं प्रतीक्षितुं शक्नुवन्ति ।
यदा मूल्यं 0 भवति तदा तस्य अर्थः अस्ति यत् वर्तमानः महत्त्वपूर्णः संसाधनः अन्यैः सूत्रैः आक्रान्तः अस्ति तथा च महत्त्वपूर्णविभागे प्रवेशं कर्तुं न शक्नोति तथा च केवलं प्रतीक्षां कर्तुं शक्नोति ।

म्यूटेक्स-तालानां लक्षणम्

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
  • mutex lock एकः pthread_mutex_t प्रकारस्य चरः अस्ति, यः mutex lock इत्यस्य प्रतिनिधित्वं करोति ।
  • यदि द्वौ थ्रेड् एकमेव pthread_mutex_t चरं अभिगच्छन्ति, तर्हि ते समानं mutex lock अभिगच्छन्ति
  • तत्सम्बद्धाः चराः pthreadtypes.h शीर्षकसञ्चिकायां परिभाषिताः सन्ति, यत् संरचनायुक्तं सामान्यं शरीरम् अस्ति ।

म्यूटेक्स-तालानां उपयोगः

थ्रेड् म्यूटेक्स् लॉक् इत्यस्य आरम्भस्य मुख्यौ उपायौ स्तः ।

स्थिर आरम्भीकरण

  • pthread_mutex_t प्रकारस्य चरं परिभाष्य PTHREAD_MUTEX_INITIALIZER इत्यत्र आरभत ।
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER
  • 1

गतिशील आरम्भीकरण

गतिशीलप्रारम्भः गतिशीलप्रारम्भीकरणे मुख्यतया द्वौ कार्यौ भवतः: pthread_mutex_init फंक्शन् तथा pthread_mutex_destroy फंक्शन् च

pthread_mutex_init () फ़ंक्शन

म्यूटेक्स-लॉक् इत्यस्य आरम्भार्थं उपयुज्यते, एतत् द्वौ पैरामीटर् स्वीकुर्वति: म्यूटेक्स-लॉक् इत्यस्य पता, म्यूटेक्स-लॉक् इत्यस्य विशेषताः च ।

कार्यशीर्षकसञ्चिका : १.

#include <pthread.h>

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

पैरामीटर् विवरणम् : १.

  • mutex: pthread_mutex_t प्रकारस्य सूचकः, mutex lock इत्यस्य पतां संग्रहीतुं उपयुज्यते ।
  • attr: mutex lock इत्यस्य विशेषता, यत् NULL भवितुम् अर्हति, पूर्वनिर्धारितविशेषतायाः उपयोगः इति सूचयति ।

return value: 1.1.

  • 0: आरम्भीकरणं सफलम्।
  • विफलतायां त्रुटिसङ्केतः प्रत्यागच्छति ।
pthread_mutex_destroy () फ़ंक्शन

mutex lock इत्यस्य नाशार्थं प्रयुक्तः, एतत् एकं पैरामीटर् स्वीकुर्वति: mutex lock इत्यस्य पता ।

कार्यशीर्षकसञ्चिका : १.

#include <pthread.h>

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

पैरामीटर् विवरणम् : १.

  • mutex: pthread_mutex_t प्रकारस्य सूचकः, mutex lock इत्यस्य पतां संग्रहीतुं उपयुज्यते ।

return value: 1.1.

  • ०: विनाशः सफलः ।
  • विफलतायां त्रुटिसङ्केतः प्रत्यागच्छति ।

उदाहरण:

// 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

सूत्र समन्वयनम्

धागा समन्वयनम् : परस्परं बहिष्कारस्य आधारेण (अधिकांशेषु सन्दर्भेषु) अन्यतन्त्रैः आगन्तुकानां संसाधनानाम् क्रमेण प्रवेशं निर्दिशति ।

कण्डिशन् वेरिएबल : थ्रेड् लाइब्रेरी द्वारा विशेषतया थ्रेड् समन्वयनार्थं प्रदत्तं तन्त्रम् ।

सूत्रसमन्वयनार्थं एकः विशिष्टः अनुप्रयोगपरिदृश्यः उत्पादकानां उपभोक्तृणां च मध्ये भवति ।

उत्पादकस्य उपभोक्तृस्य च विषयाः

अस्मिन् प्रतिरूपे उत्पादकसूत्रे उपभोक्तृसूत्रे च विभक्तं भवति, अनेकसूत्राणां समन्वयनप्रक्रिया अस्मिन् सूत्रेण अनुकरणं भवति

अस्मिन् प्रतिरूपे निम्नलिखितघटकाः आवश्यकाः सन्ति ।

  • गोदामः उत्पादानाम् संग्रहणार्थं प्रयुक्तः, सामान्यतया साझासंसाधनरूपेण
  • उत्पादकसूत्रः उत्पादानाम् उत्पादनार्थं प्रयुक्तः
  • उपभोक्तृसूत्रः उत्पादानाम् उपभोगार्थं प्रयुक्तः

सिद्धान्तः १.

यदा गोदामे उत्पादः नास्ति तदा उपभोक्तृसूत्रस्य उपभोगं कर्तुं पूर्वं यावत् उत्पादः नास्ति तावत् प्रतीक्षितव्यम् ।

यदा गोदामः उत्पादैः पूरितः भवति तदा उत्पादकसूत्रस्य प्रतीक्षा भवति यावत् उपभोक्तृसूत्रः उत्पादानाम् उपभोगं न करोति ।

म्यूटेक्स-तालाधारितं उत्पादक-उपभोक्तृ-प्रतिरूपं कार्यान्वितुं उदाहरणम्

मुख्यसूत्रः उपभोक्ता अस्ति

न उपसूत्राणि उत्पादकत्वेन

// 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

शर्त चर

कण्डिशन् वेरिएबल इति समन्वयनतन्त्रं यत् थ्रेड् इत्यस्य निरन्तरं चालनपूर्वं निश्चितं कण्डिशन् पूरयितुं प्रतीक्षां कर्तुं शक्नोति ।

कण्डिशन् वेरियेबल् इत्यस्य सिद्धान्तः अस्ति यत् तस्मिन् म्यूटेक्स् लॉक्, प्रतीक्षमाणा कतारं च भवति ।

प्रतीक्षमाणानां कतारानाम्, कण्डिशन् चरानाम् रक्षणार्थं म्यूटेक्स् लॉक् इत्यस्य उपयोगः भवति ।

अत्र चित्रविवरणं सम्मिलितं कुर्वन्तु

कंडीशन चर इनिशियलाइजेशन

कण्डिशन् चरस्य प्रकृतिः 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

कण्डिशन् चरानाम् आरम्भीकरणं स्थिरप्रारम्भीकरणं गतिशीलप्रारम्भीकरणं च इति विभक्तं भवति ।

स्थिर आरम्भीकरण

स्थिररूपेण आरम्भितानां कण्डिशन् चरानाम् कृते, भवद्भिः प्रथमं pthread_cond_t प्रकारस्य चरं परिभाषितव्यं, ततः PTHREAD_COND_INITIALIZER इत्यत्र आरभणीयम् ।

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  • 1

गतिशील आरंभीकरण pthread_cond_init () .

गतिशीलरूपेण कण्डिशन् चरस्य आरम्भार्थं प्रथमं pthread_cond_t प्रकारस्य चरं परिभाषितुं आवश्यकं, ततः तस्य आरम्भार्थं pthread_cond_init फंक्शन् आह्वयितुं आवश्यकम् ।

कार्यशीर्षकसञ्चिका : १.

#include <pthread.h>

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

पैरामीटर् विवरणम् : १.

  • cond: pthread_cond_t प्रकारस्य सूचकः, कण्डिशन् चरस्य पतां संग्रहीतुं उपयुज्यते ।
  • attr: condition variable इत्यस्य attribute, यत् default attribute इत्यस्य उपयोगाय NULL भवितुम् अर्हति ।

return value: 1.1.

  • 0: आरम्भीकरणं सफलम्।
  • विफलतायां त्रुटिसङ्केतः प्रत्यागच्छति ।

pthread_cond_destroy () 1.1.

कण्डिशन् चरस्य नाशार्थं उपयुज्यते, एतत् एकं पैरामीटर् स्वीकुर्वति: कण्डिशन् चरस्य पता ।

कार्यशीर्षकसञ्चिका : १.

#include <pthread.h>

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

पैरामीटर् विवरणम् : १.

  • cond: pthread_cond_t प्रकारस्य सूचकः, कण्डिशन् चरस्य पतां संग्रहीतुं उपयुज्यते ।

return value: 1.1.

  • ०: विनाशः सफलः ।
  • विफलतायां त्रुटिसङ्केतः प्रत्यागच्छति ।

शर्तचरानाम् उपयोगः

कण्डिशन् वेरियेबल् इत्यस्य उपयोगः प्रतीक्षा, सूचना च इति विभक्तः अस्ति

pthread_cond_wait() इत्यस्य प्रतीक्षां कुर्वन्तु।

प्रतीक्षाकार्यं pthread_cond_wait() त्रयः पैरामीटर्स् स्वीकुर्वति: कण्डिशन् चरस्य पता, म्यूटेक्स् लॉकस्य पता, प्रतीक्षासमयः च ।

कार्यशीर्षकसञ्चिका : १.

#include <pthread.h>

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

पैरामीटर् विवरणम् : १.

  • cond: pthread_cond_t प्रकारस्य सूचकः, कण्डिशन् चरस्य पतां संग्रहीतुं उपयुज्यते ।
  • mutex: pthread_mutex_t प्रकारस्य सूचकः, mutex lock इत्यस्य पतां संग्रहीतुं उपयुज्यते ।
  • abstime: समयसमाप्तिः, यत् NULL भवितुम् अर्हति, यत् समयसमाप्तिः नास्ति इति सूचयति ।

return value: 1.1.

  • 0: सफलतायाः प्रतीक्षां कुर्वन्तु।
  • विफलतायां त्रुटिसङ्केतः प्रत्यागच्छति ।

pthread_cond_signal () इति सूचितं कुर्वन्तु।

सूचना कार्य
pthread_cond_signal() एकं पैरामीटर् स्वीकुर्वति: कण्डिशन् चरस्य पता ।

कार्यशीर्षकसञ्चिका : १.

#include <pthread.h>

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

पैरामीटर् विवरणम् : १.

  • cond: pthread_cond_t प्रकारस्य सूचकः, कण्डिशन् चरस्य पतां संग्रहीतुं उपयुज्यते ।

return value: 1.1.

  • 0: सूचना सफला।
  • विफलतायां त्रुटिसङ्केतः प्रत्यागच्छति ।

सर्वाणि pthread_cond_broadcast() सूचयन्तु।

सर्वाणि कार्याणि सूचयन्तु
pthread_cond_broadcast() एकं पैरामीटर् स्वीकुर्वति: कण्डिशन् चरस्य पता ।

कार्यशीर्षकसञ्चिका : १.

#include <pthread.h>

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

पैरामीटर् विवरणम् : १.

  • cond: pthread_cond_t प्रकारस्य सूचकः, कण्डिशन् चरस्य पतां संग्रहीतुं उपयुज्यते ।

return value: 1.1.

  • 0: सूचना सफला।
  • विफलतायां त्रुटिसङ्केतः प्रत्यागच्छति ।

सशर्तचरानाम् आधारेण उत्पादकस्य उपभोक्तृणां च आदर्शानां कार्यान्वयनस्य उदाहरणम्

अत्र चित्रविवरणं सम्मिलितं कुर्वन्तु

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

म्यूटेक्स-लॉक्-सहितं कण्डिशन्-चरानाम् उपयोगः किमर्थं आवश्यकः ?

साझादत्तांशस्य रक्षणं कुर्वन्तु : १.

साझादत्तांशस्य रक्षणार्थं तथा च केवलं एकः सूत्रः एकस्मिन् समये दत्तांशं अभिगन्तुं परिवर्तयितुं च शक्नोति इति सुनिश्चित्य Mutex तालानां उपयोगः भवति ।

एतेन दत्तांशजातिः, असङ्गतिः च परिहृता भवति ।

अन्यसूत्राणां कृते कश्चन कण्डिशन् पूरितः इति सूचयितुं थ्रेड्-मध्ये संचारार्थं कण्डिशन्-चरानाम् उपयोगः भवति ।

परन्तु कण्डिशन् वेरबल् इत्यस्य संचालनं स्वयमेव साझादत्तांशस्य रक्षणं न ददाति अतः म्यूटेक्स् लॉक् इत्यनेन सह संयोजनेन तस्य उपयोगः आवश्यकः ।

मिथ्या जागरणं परिहरन्तु : १.

शर्तचरानाम् एकं लक्षणं अस्ति यत् मिथ्या जागरणं भवितुम् अर्हति ।

स्पष्टं सूचनां विना सूत्रं जागर्यते इत्यर्थः । अस्याः परिस्थित्याः कारणेन अशुद्धक्रियाः परिहरितुं

सूत्रेण पुनः परीक्षणं करणीयम् यत् जागरणानन्तरं शर्तः वास्तवतः पूरिता अस्ति वा इति ।

म्यूटेक्सस्य उपयोगेन सुनिश्चितं भवति यत् परिस्थितिपरीक्षायां साझादत्तांशः अन्यैः सूत्रैः परिवर्तितः न भवति, अतः मिथ्याजागरणजन्यदोषाः परिहृताः भवन्ति ।

सूचना सम्यक् अस्ति इति सुनिश्चितं कुर्वन्तु:

यदा कश्चन थ्रेड् अन्यथ्रेड्-आन् कण्डिशन्-चर-माध्यमेन सूचयति तदा तस्य सूचनां दातुं पूर्वं साझा-दत्तांशः अद्यतनः अभवत् इति सुनिश्चितं कर्तव्यम् ।

एकः म्यूटेक्सः एतस्य गारण्टीं ददाति, यत् सुनिश्चितं करोति यत् सर्वाणि दत्तांश-अद्यतन-कार्यक्रमाः तालान् मुक्तुं पूर्वं सम्पन्नाः सन्ति ।

तथैव सूचनां प्राप्य सूत्रेण कण्डिशन् परीक्षितुं पूर्वं म्यूटेक्स् धारयितुं आवश्यकं भवति यत् कण्डिशन् परीक्षिते सति दत्तांशः स्थिरः भवति इति सुनिश्चितं भवति

जटिल समन्वयनप्रतिमानं कार्यान्वितम् : १.
म्यूटेक्स-लॉक्-इत्यस्य कण्डिशन्-चर-सहितं संयोजनेन अधिकजटिल-समन्वयन-प्रतिमानं कार्यान्वितुं शक्यते, यथा उत्पादक-उपभोक्तृ-समस्याः, पाठक-लेखक-समस्याः इत्यादयः म्यूटेक्स् साझादत्तांशस्य रक्षणं करोति, तथा च थ्रेड्-मध्ये समन्वयस्य संचारस्य च कृते कण्डिशन्-चरानाम् उपयोगः भवति ।

// 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