热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linux环境下多线程编程实战案例分析

在Linux环境下,多线程编程是实现高效并发处理的重要技术。本文通过具体的实战案例,详细分析了多线程编程的关键技术和常见问题。文章首先介绍了多线程的基本概念和创建方法,然后通过实例代码展示了如何使用pthreads库进行线程同步和通信。此外,还探讨了多线程程序中的性能优化技巧和调试方法,为开发者提供了宝贵的实践经验。

参考:

http://www.cnblogs.com/armlinux/archive/2010/05/28/2396997.html

http://blog.csdn.net/hitwengqi/article/details/8015646

http://www.vimer.cn/2009/11/linux%E4%B8%8B%E5%A4%9A%E7%BA%BF%E7%A8%8B%E7%9A%84%E5%88%9B%E5%BB%BA%E4%B8%8E%E7%AD%89%E5%BE%85%E8%AF%A6%E8%A7%A3.html

http://www.cnblogs.com/skynet/archive/2010/10/30/1865267.html

http://www.cnblogs.com/vamei/archive/2012/10/09/2715393.html



最近在优化一个图像处理算法,算法中要对于不同的图片做相同的图像处理算法,不同图片之间的处理数据时独立的,因而很自然的想到利用多线程优化算法。

下面是一些学习代码

一 Linux下面的多线编程需要包含明白以下几点:

1 pthread_t
       pthread_t在头文件/usr/include/bits/pthreadtypes.h中定义:
  typedef unsigned long int pthread_t;
  它是一个线程的标识符。

2 pthread_create
      函数pthread_create用来创建一个线程,它的原型为:
      extern int pthread_create __P ((pthread_t *__thread, __const pthread_attr_t *__attr,
  void *(*__start_routine) (void *), void *__arg));
       第一个参数为指向线程标识符的指针;

第二个参数用来设置线程属性;

第三个参数是线程运行函数的起始地址;

最后一个参数是运行函数的参数。

这里,我们的函数thread不需要参数,所以最后一个参数设为空指针。

第二个参数我们也设为空指针,这样将生成默认属性的线程。

对线程属性的设定和修改我们将在下一节 阐述。

当创建线程成功时,函数返回0,若不为0则说明创建线程失败,常见的错误返回代码为EAGAIN和EINVAL。

前者表示系统限制创建新的线程,例 如线程数目过多了;

后者表示第二个参数代表的线程属性值非法。

创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,

原来的线程则继续运行下一行 代码。

3 pthread_join 和pthread_exit
       函数pthread_join用来等待一个线程的结束。函数原型为:
  extern int pthread_join __P ((pthread_t __th, void **__thread_return));
       第一个参数为被等待的线程标识符;

第二个参数为一个用户定义的指针;

它可以用来存储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的函数将 一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。一个线程的结束有两种途径,一种是像我们上面的例子一样,函数结束了,调用它的 线程也就结束了;

另一种方式是通过函数pthread_exit来实现。它的函数原型为:
  extern void pthread_exit __P ((void *__retval)) __attribute__ ((__noreturn__));
   唯一的参数是函数的返回代码,只要pthread_join中的第二个参数thread_return不是NULL,这个值将被传递给 thread_return。

最后要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join的线 程则返回错误代码ESRCH。
  在这一节里,我们编写了一个最简单的线程,并掌握了最常用的三个函数pthread_create,pthread_join和pthread_exit。

4 互斥锁相关
互斥锁用来保证一段时间内只有一个线程在执行一段代码。

pthread_mutex_init函数用来生成一个互斥锁。NULL参数表明使用默认属性。如果需要声明特定属性的互斥锁,须调用函数 pthread_mutexattr_init。函数pthread_mutexattr_setpshared和函数 pthread_mutexattr_settype用来设置互斥锁属性。前一个函数设置属性pshared,它有两个取值, PTHREAD_PROCESS_PRIVATE;

PTHREAD_PROCESS_SHARED;

前者用来不同进程中的线程同步,后者用于同步本进程的 不同线程。

在上面的例子中,我们使用的是默认属性PTHREAD_PROCESS_ PRIVATE。后者用来设置互斥锁类型,可选的类型有

PTHREAD_MUTEX_NORMAL、

PTHREAD_MUTEX_ERRORCHECK、

PTHREAD_MUTEX_RECURSIVE和

PTHREAD _MUTEX_DEFAULT。

它们分别定义了不同的上所、解锁机制,一般情况下,选用最后一个默认属性。
pthread_mutex_lock和 pthread_mutex_unlock以及pthread_delay_np
pthread_mutex_lock声明开始用互斥锁上锁,此后的代码直至调用pthread_mutex_unlock为止,均被上锁,即同一时间只 能被一个线程调用执行。当一个线程执行到pthread_mutex_lock处时,如果该锁此时被另一个线程使用,那此线程被阻塞,即程序将等待到另一 个线程释放此互斥锁。

 

二 简单的代码实例

 

[cpp] view plaincopy
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. using namespace std;  
  7.   
  8. pthread_t thread[2];  
  9. pthread_mutex_t mut;  
  10. double array[10][10];  
  11.   
  12. double funtime(const string &str)  
  13. {  
  14.     struct timeval tpstart,tpend;  
  15.     double timeuse;  
  16.     gettimeofday(&tpstart,NULL);  
  17.   
  18.     int loop = 1000000;  
  19.     while(loop--)  
  20.     {  
  21.         for (int i &#61; 0; i < 10; &#43;&#43;i)  
  22.         {  
  23.             for(int j &#61; 0; j < 10;&#43;&#43;j)  
  24.             {  
  25.                 array[i][j] &#61; 0.63;  
  26.                 array[i][j] /&#61; 0.96;  
  27.             }  
  28.         }  
  29.     }  
  30.     gettimeofday(&tpend,NULL);  
  31.     timeuse&#61;1000000*(tpend.tv_sec-tpstart.tv_sec)&#43;tpend.tv_usec-tpstart.tv_usec;  
  32.     timeuse/&#61;1000;  
  33.     cout << str << " timeuse: " << timeuse << " ms" << endl;  
  34.     return timeuse;  
  35. }  
  36.   
  37.   
  38. void *thread1(void *args)  
  39. {  
  40.     cout<< "thread1 : I&#39;m thread 1" << endl;  
  41.     funtime("thread1 fun");  
  42.     cout<< "thread1 :main function is waiting me" << endl;  
  43.     pthread_exit(NULL);  
  44. }  
  45.   
  46. void *thread2(void *args)  
  47. {  
  48.     cout<< "thread2 : I&#39;m thread 2" << endl;  
  49.     funtime("thread2 fun");  
  50.     cout<< "thread2 :main function is waiting me" << endl;  
  51.     pthread_exit(NULL);  
  52. }  
  53.   
  54. void thread_create(void)  
  55. {  
  56.     int temp;  
  57.     memset(&thread, 0, sizeof(thread));            
  58.     if((temp &#61; pthread_create(&thread[0], NULL, thread1, NULL)) !&#61; 0)       
  59.         cout<<"thread1 is created failed" << endl;  
  60.     else  
  61.         cout<<"thread1 is created " << endl;  
  62.     if((temp &#61; pthread_create(&thread[1], NULL, thread2, NULL)) !&#61; 0)    
  63.         cout<<"thread2 created failed" << endl;  
  64.     else  
  65.         cout<<"thread2 is created" << endl;  
  66. }  
  67.   
  68. void thread_wait(void)  
  69. {  
  70.     if(thread[0] !&#61;0)  
  71.     {       
  72.         pthread_join(thread[0],NULL);  
  73.         cout<<("thread1 is end \n");  
  74.     }  
  75.     if(thread[1] !&#61;0)   
  76.     {    
  77.         pthread_join(thread[1],NULL);  
  78.         cout<<("thread2 is end \n");  
  79.     }  
  80. }  
  81.   
  82.   
  83. int main()  
  84. {  
  85.     struct timeval tpstart,tpend;  
  86.     double timeuse;  
  87.     gettimeofday(&tpstart,NULL);  
  88.   
  89.     pthread_mutex_init(&mut,NULL);  
  90.     cout<<"main function is created thread" << endl;  
  91.     thread_create();  
  92.     cout<<"main function is waiting thread" << endl;  
  93.     thread_wait();  
  94.   
  95.     gettimeofday(&tpend,NULL);  
  96.     timeuse&#61;1000000*(tpend.tv_sec-tpstart.tv_sec)&#43;tpend.tv_usec-tpstart.tv_usec;  
  97.     timeuse/&#61;1000;  
  98.     cout << "MulThread " << " timeuse: " << timeuse << " ms" << endl;  
  99.   
  100.     cout << "signle thread time using: " <<   
  101.     funtime("main fun") &#43; funtime("main fun") << " ms" << endl;  
  102.   
  103.     return 0;  
  104. }  







测试运行&#xff1a;

linux 平台下面编译时需要加上 -lpthrad 如上面的代码test.cpp , 编译命令&#xff1a;

  g&#43;&#43;  -o test test.cpp -lpthread

可以看到两个线程都开始运行了&#xff0c;执行一次funtime函数需要花费1000ms左右的时间&#xff0c;单线程执行两次需要花费1953ms&#xff0c;而多线程利用两个线程并行执行花费的时间为1031ms&#xff0c;总的时间缩短了接近一倍。

为了验证多线程程序的执行结果是否正确&#xff0c;可以打印出矩阵观察。

修改代码&#xff1a;

[cpp] view plaincopy
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. using namespace std;  
  7.   
  8. pthread_t thread[2];  
  9. pthread_mutex_t mut;  
  10.   
  11. double array1[10][10];  
  12. double array2[10][10];  
  13. double array0[10][10];  
  14.   
  15. double funtime(const string &str, const int index)  
  16. {  
  17.     struct timeval tpstart,tpend;  
  18.     double timeuse;  
  19.     gettimeofday(&tpstart,NULL);  
  20.   
  21.     int loop &#61; 1000000;  
  22.     while(loop--)  
  23.     {  
  24.         for (int i &#61; 0; i < 10; &#43;&#43;i)  
  25.         {  
  26.             for(int j &#61; 0; j < 10;&#43;&#43;j)  
  27.             {  
  28.                 if (index &#61;&#61; 1)  
  29.                 {  
  30.                     array1[i][j] &#61; 1;  
  31.                     array1[i][j] /&#61; 2;  
  32.                 }else if(index &#61;&#61; 2)  
  33.                 {  
  34.                     array2[i][j] &#61; 2;  
  35.                     array2[i][j] /&#61; 2;  
  36.                 }else  
  37.                 {  
  38.                     array0[i][j] &#61; 3;  
  39.                     array0[i][j] /&#61; 2;  
  40.                 }  
  41.             }  
  42.         }  
  43.     }  
  44.   
  45.     gettimeofday(&tpend,NULL);  
  46.     timeuse&#61;1000000*(tpend.tv_sec-tpstart.tv_sec)&#43;tpend.tv_usec-tpstart.tv_usec;  
  47.     timeuse/&#61;1000;  
  48.     cout << str << " timeuse: " << timeuse << " ms" << endl;  
  49.     return timeuse;  
  50. }  
  51.   
  52.   
  53. void *thread1(void *args)  
  54. {  
  55.     cout<< "thread1 : I&#39;m thread 1" << endl;  
  56.     funtime("thread1 fun",1);  
  57.     cout<< "thread1 :main function is waiting me" << endl;  
  58.     pthread_exit(NULL);  
  59. }  
  60.   
  61. void *thread2(void *args)  
  62. {  
  63.     cout<< "thread2 : I&#39;m thread 2" << endl;  
  64.     funtime("thread2 fun",2);  
  65.     cout<< "thread2 :main function is waiting me" << endl;  
  66.     pthread_exit(NULL);  
  67. }  
  68.   
  69. void thread_create(void)  
  70. {  
  71.     int temp;  
  72.     memset(&thread, 0, sizeof(thread));            
  73.     if((temp &#61; pthread_create(&thread[0], NULL, thread1, NULL)) !&#61; 0)       
  74.         cout<<"thread1 is created failed" << endl;  
  75.     else  
  76.         cout<<"thread1 is created " << endl;  
  77.     if((temp &#61; pthread_create(&thread[1], NULL, thread2, NULL)) !&#61; 0)    
  78.         cout<<"thread2 created failed" << endl;  
  79.     else  
  80.         cout<<"thread2 is created" << endl;;  
  81. }  
  82.   
  83. void thread_wait(void)  
  84. {  
  85.     if(thread[0] !&#61;0)  
  86.     {       
  87.         pthread_join(thread[0],NULL);  
  88.         cout<<("thread1 is end \n");  
  89.     }  
  90.     if(thread[1] !&#61;0)   
  91.     {    
  92.         pthread_join(thread[1],NULL);  
  93.         cout<<("thread2 is end \n");  
  94.     }  
  95. }  
  96.   
  97.   
  98. void printresult()  
  99. {  
  100.     cout << "array1" << endl;  
  101.     for (int i &#61; 0; i < 10; &#43;&#43;i)  
  102.     {  
  103.         for (int j &#61; 0; j < 10; &#43;&#43;j)  
  104.         {  
  105.             cout << " " << array1[i][j];  
  106.         }  
  107.         cout << endl;  
  108.     }  
  109.   
  110.     cout <<"array2" <
  111.     for (int i &#61; 0; i < 10; &#43;&#43;i)  
  112.     {  
  113.         for (int j &#61; 0; j < 10; &#43;&#43;j)  
  114.         {  
  115.             cout << " " << array2[i][j];  
  116.         }  
  117.         cout << endl;  
  118.     }  
  119.   
  120.     cout <<"array0" <
  121.     for (int i &#61; 0; i < 10; &#43;&#43;i)  
  122.     {  
  123.         for (int j &#61; 0; j < 10; &#43;&#43;j)  
  124.         {  
  125.             cout << " " << array0[i][j];  
  126.         }  
  127.         cout << endl;  
  128.     }  
  129.   
  130. }  
  131.   
  132.   
  133. int main()  
  134. {  
  135.     struct timeval tpstart,tpend;  
  136.     double timeuse;  
  137.     gettimeofday(&tpstart,NULL);  
  138.   
  139.     pthread_mutex_init(&mut,NULL);  
  140.     cout<<"main function is created thread" << endl;  
  141.     thread_create();  
  142.     cout<<"main function is waiting thread" << endl;  
  143.     thread_wait();  
  144.   
  145.     gettimeofday(&tpend,NULL);  
  146.     timeuse&#61;1000000*(tpend.tv_sec-tpstart.tv_sec)&#43;tpend.tv_usec-tpstart.tv_usec;  
  147.     timeuse/&#61;1000;  
  148.     cout << "MulThread " << " timeuse: " << timeuse << " ms" << endl;  
  149.   
  150.     cout << "signle thread time using: " <<   
  151.     funtime("main fun",0) &#43; funtime("main fun",0) << " ms" << endl;  
  152.   
  153.     printresult();  
  154.   
  155.     return 0;  
  156. }  



从中可以看出线程执行结果是正确的

三 线程函数参数传递

funtime("thread1 fun",1);

funtime函数为线程调用中的主要执行函数&#xff0c;包含两个参数&#xff0c;都被写死了&#xff0c;实际中会有很多限制&#xff0c;因此需要考虑从线程的入口处传入参数。

前面的代码中&#xff0c;pthread_create(&thread[0], NULL, thread1, NULL)) !&#61; 0)中&#xff0c;第四个参数是线程执行函数需要传入的参数&#xff0c;在线程函数中void *thread1(void *args)中&#xff0c;只能允许传入一个参数&#xff0c;如果要传入多个参数&#xff0c;需要使用结构体&#xff0c;将多个参数组合为一个结构体一起传入。实例如下&#xff1a;

代码如下

[cpp] view plaincopy
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. using namespace std;  
  7.   
  8. //thread function pamter  
  9. struct theradPamter{  
  10.     int threadindex;  
  11.     string str;  
  12. };  
  13.   
  14. pthread_t thread[2];  
  15. pthread_mutex_t mut;  
  16.   
  17. double array1[10][10];  
  18. double array2[10][10];  
  19. double array0[10][10];  
  20.   
  21.   
  22. double funtime(const string &str, const int index)  
  23. {  
  24.     struct timeval tpstart,tpend;  
  25.     double timeuse;  
  26.     gettimeofday(&tpstart,NULL);  
  27.   
  28.     int loop &#61; 1000000;  
  29.     while(loop--)  
  30.     {  
  31.         for (int i &#61; 0; i < 10; &#43;&#43;i)  
  32.         {  
  33.             for(int j &#61; 0; j < 10;&#43;&#43;j)  
  34.             {  
  35.                 if (index &#61;&#61; 1)  
  36.                 {  
  37.                     array1[i][j] &#61; 1;  
  38.                     array1[i][j] /&#61; 2;  
  39.                 }else if(index &#61;&#61; 2)  
  40.                 {  
  41.                     array2[i][j] &#61; 2;  
  42.                     array2[i][j] /&#61; 2;  
  43.                 }else  
  44.                 {  
  45.                     array0[i][j] &#61; 3;  
  46.                     array0[i][j] /&#61; 2;  
  47.                 }  
  48.             }  
  49.         }  
  50.     }  
  51.   
  52.     gettimeofday(&tpend,NULL);  
  53.     timeuse&#61;1000000*(tpend.tv_sec-tpstart.tv_sec)&#43;tpend.tv_usec-tpstart.tv_usec;  
  54.     timeuse/&#61;1000;  
  55.     cout << str << " timeuse: " << timeuse << " ms" << endl;  
  56.     return timeuse;  
  57. }  
  58.   
  59.   
  60. void *thread1(void *args)  
  61. {  
  62.     cout<< "thread1 : I&#39;m thread 1" << endl;  
  63.     theradPamter *tp &#61; (theradPamter *) args;  
  64.     funtime(tp->str, tp->threadindex);  
  65.     cout<< "thread1 :main function is waiting me" << endl;  
  66.     pthread_exit(NULL);  
  67. }  
  68.   
  69. void *thread2(void *args)  
  70. {  
  71.     cout<< "thread2 : I&#39;m thread 2" << endl;  
  72.     theradPamter *tp &#61; (theradPamter *) args;  
  73.     funtime(tp->str, tp->threadindex);  
  74.     cout<< "thread2 :main function is waiting me" << endl;  
  75.     pthread_exit(NULL);  
  76. }  
  77.   
  78. void thread_create(theradPamter *tp1, theradPamter *tp2)  
  79. {  
  80.     int temp;  
  81.     memset(&thread, 0, sizeof(thread));  
  82.       
  83.     if((temp &#61; pthread_create(&thread[0], NULL, thread1, (void *)tp1)) !&#61; 0)       
  84.         cout<<"thread1 is created failed" << endl;  
  85.     else  
  86.         cout<<"thread1 is created " << endl;  
  87.     if((temp &#61; pthread_create(&thread[1], NULL, thread2, (void *)tp2)) !&#61; 0)    
  88.         cout<<"thread2 created failed" << endl;  
  89.     else  
  90.         cout<<"thread2 is created" << endl;  
  91.   
  92. }  
  93.   
  94. void thread_wait(void)  
  95. {  
  96.     if(thread[0] !&#61;0)  
  97.     {       
  98.         pthread_join(thread[0],NULL);  
  99.         cout<<("thread1 is end \n");  
  100.     }  
  101.     if(thread[1] !&#61;0)   
  102.     {    
  103.         pthread_join(thread[1],NULL);  
  104.         cout<<("thread2 is end \n");  
  105.     }  
  106. }  
  107.   
  108.   
  109. void printresult()  
  110. {  
  111.     cout << "array1" << endl;  
  112.     for (int i &#61; 0; i < 10; &#43;&#43;i)  
  113.     {  
  114.         for (int j &#61; 0; j < 10; &#43;&#43;j)  
  115.         {  
  116.             cout << " " << array1[i][j];  
  117.         }  
  118.         cout << endl;  
  119.     }  
  120.   
  121.     cout <<"array2" <
  122.     for (int i &#61; 0; i < 10; &#43;&#43;i)  
  123.     {  
  124.         for (int j &#61; 0; j < 10; &#43;&#43;j)  
  125.         {  
  126.             cout << " " << array2[i][j];  
  127.         }  
  128.         cout << endl;  
  129.     }  
  130.   
  131.     cout <<"array0" <
  132.     for (int i &#61; 0; i < 10; &#43;&#43;i)  
  133.     {  
  134.         for (int j &#61; 0; j < 10; &#43;&#43;j)  
  135.         {  
  136.             cout << " " << array0[i][j];  
  137.         }  
  138.         cout << endl;  
  139.     }  
  140.   
  141. }  
  142.   
  143.   
  144. int main()  
  145. {  
  146.     struct timeval tpstart,tpend;  
  147.     double timeuse;  
  148.     gettimeofday(&tpstart,NULL);  
  149.   
  150.     pthread_mutex_init(&mut,NULL);  
  151.     cout<<"main function is created thread" << endl;  
  152.   
  153.     theradPamter *tp1 &#61; new theradPamter;  
  154.     theradPamter *tp2 &#61; new theradPamter;    
  155.     tp1->threadindex &#61; 1;  
  156.     tp1->str &#61; "thread1 fun";    
  157.     tp2->threadindex &#61; 2;  
  158.     tp2->str &#61; "thread2 fun";    
  159.   
  160.     thread_create(tp1, tp2);  
  161.   
  162.     cout<<"main function is waiting thread" << endl;  
  163.     thread_wait();  
  164.   
  165.     delete tp1;  
  166.     tp1 &#61; NULL;  
  167.     delete tp2;  
  168.     tp2 &#61; NULL;  
  169.   
  170.     gettimeofday(&tpend,NULL);  
  171.     timeuse&#61;1000000*(tpend.tv_sec-tpstart.tv_sec)&#43;tpend.tv_usec-tpstart.tv_usec;  
  172.     timeuse/&#61;1000;  
  173.     cout << "MulThread " << " timeuse: " << timeuse << " ms" << endl;  
  174.   
  175.     cout << "signle thread time using: " <<   
  176.     funtime("main fun",0) &#43; funtime("main fun",0) << " ms" << endl;  
  177.   
  178.     printresult();  
  179.   
  180.     return 0;  
  181. }  



线程函数的参数需要传入一个void *类型的指针&#xff0c;因此需要在传递时&#xff0c;将tp指针强制转化为void*类型&#xff0c;传入 thread1(void *args) 中

在thread1(void *args)函数内&#xff0c;使用该指针时&#xff0c;在强制类型转换为threadPamter类型。


推荐阅读
  • 在Android平台上,视频监控系统的优化与应用具有重要意义。尽管已有相关示例(如http:www.open-open.comlibviewopen1346400423609.html)展示了基本的监控功能实现,但若要提升系统的稳定性和性能,仍需进行深入研究和优化。本文探讨了如何通过改进算法、优化网络传输和增强用户界面来提高Android视频监控系统的整体效能,以满足更复杂的应用需求。 ... [详细]
  • CTF竞赛中文件上传技巧与安全绕过方法深入解析
    CTF竞赛中文件上传技巧与安全绕过方法深入解析 ... [详细]
  • 2018年9月21日,Destoon官方发布了安全更新,修复了一个由用户“索马里的海贼”报告的前端GETShell漏洞。该漏洞存在于20180827版本的某CMS中,攻击者可以通过构造特定的HTTP请求,利用该漏洞在服务器上执行任意代码,从而获得对系统的控制权。此次更新建议所有用户尽快升级至最新版本,以确保系统的安全性。 ... [详细]
  • 在前文探讨了Spring如何为特定的bean选择合适的通知器后,本文将进一步深入分析Spring AOP框架中代理对象的生成机制。具体而言,我们将详细解析如何通过代理技术将通知器(Advisor)中包含的通知(Advice)应用到目标bean上,以实现切面编程的核心功能。 ... [详细]
  • 本文深入解析了Bitmap与Byte数组之间高效转换的方法,探讨了不同场景下的最优实现策略,提供了详尽的代码示例和性能对比分析,旨在帮助开发者在图像处理和数据传输中提升效率和减少资源消耗。 ... [详细]
  • 在当前的软件开发领域,Lua 作为一种轻量级脚本语言,在 .NET 生态系统中的应用逐渐受到关注。本文探讨了 Lua 在 .NET 环境下的集成方法及其面临的挑战,包括性能优化、互操作性和生态支持等方面。尽管存在一定的技术障碍,但通过不断的学习和实践,开发者能够克服这些困难,拓展 Lua 在 .NET 中的应用场景。 ... [详细]
  • 基于Dubbo与Zipkin的微服务调用链路监控解决方案
    本文提出了一种基于Dubbo与Zipkin的微服务调用链路监控解决方案。通过抽象配置层,支持HTTP和Kafka两种数据上报方式,实现了灵活且高效的调用链路追踪。该方案不仅提升了系统的可维护性和扩展性,还为故障排查提供了强大的支持。 ... [详细]
  • 手指触控|Android电容屏幕驱动调试指南
    手指触控|Android电容屏幕驱动调试指南 ... [详细]
  • 本文对常见的字符串哈希函数进行了全面分析,涵盖了BKDRHash、APHash、DJBHash、JSHash、RSHash、SDBMHash、PJWHash和ELFHash等多种算法。这些哈希函数在不同的应用场景中表现出各异的性能特点,通过对比其算法原理、计算效率和碰撞概率,为实际应用提供了有价值的参考。 ... [详细]
  • 在Android 4.4系统中,通过使用 `Intent` 对象并设置动作 `ACTION_GET_CONTENT` 或 `ACTION_OPEN_DOCUMENT`,可以从相册中选择图片并获取其路径。具体实现时,需要为 `Intent` 添加相应的类别,并处理返回的 Uri 以提取图片的文件路径。此方法适用于需要从用户相册中选择图片的应用场景,能够确保兼容性和用户体验。 ... [详细]
  • 本文介绍了UUID(通用唯一标识符)的概念及其在JavaScript中生成Java兼容UUID的代码实现与优化技巧。UUID是一个128位的唯一标识符,广泛应用于分布式系统中以确保唯一性。文章详细探讨了如何利用JavaScript生成符合Java标准的UUID,并提供了多种优化方法,以提高生成效率和兼容性。 ... [详细]
  • Netty框架中运用Protobuf实现高效通信协议
    在Netty框架中,通过引入Protobuf来实现高效的通信协议。为了使用Protobuf,需要先准备好环境,包括下载并安装Protobuf的代码生成器`protoc`以及相应的源码包。具体资源可从官方下载页面获取,确保版本兼容性以充分发挥其性能优势。此外,配置好开发环境后,可以通过定义`.proto`文件来自动生成Java类,从而简化数据序列化和反序列化的操作,提高通信效率。 ... [详细]
  • 为了向用户提供虚拟应用程序,通常会在基础架构中部署StoreFront或Web Interface。为了确保安全的远程访问,通常需要在DMZ中配置Secure Gateway或Access Gateway。本文详细对比了这两种界面工具的功能特性,包括用户管理、安全性、性能优化等方面,为企业选择合适的解决方案提供了全面的参考。 ... [详细]
  • 在尝试对从复杂 XSD 生成的类进行序列化时,遇到了 `NullReferenceException` 错误。尽管已经花费了数小时进行调试和搜索相关资料,但仍然无法找到问题的根源。希望社区能够提供一些指导和建议,帮助解决这一难题。 ... [详细]
  • 在探讨C语言编程文本编辑器的最佳选择与专业推荐时,本文将引导读者构建一个基础的文本编辑器程序。该程序不仅能够打开并显示文本文件的内容及其路径,还集成了菜单和工具栏功能,为用户提供更加便捷的操作体验。通过本案例的学习,读者可以深入了解文本编辑器的核心实现机制。 ... [详细]
author-avatar
请让我来打酱油
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有