threaded-shared-conn.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.haxx.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. ***************************************************************************/
  22. /* <DESC>
  23. * Multi-threaded transfers sharing a single connection pool
  24. * </DESC>
  25. *
  26. * This example fires up NUM_THREADS threads and in each single thread, it
  27. * downloads the same fixed URL a URL_ITERATIONS number of times. The received
  28. * data is just thrown away. It sets up a single shared object that holds the
  29. * connection cache and all easy handles in all threads share that same cache.
  30. *
  31. * This example uses pthreads for threads and mutexes, but should be easy to
  32. * modify to use different thread/mutex system should you want to.
  33. *
  34. */
  35. #include <stdio.h>
  36. #include <pthread.h>
  37. #include <curl/curl.h>
  38. /*
  39. URL to fetch. If you select HTTPS, you need to use a TLS backend with mutex
  40. locks taken care of (OpenSSL 1.1.x, NSS, etc) or add SSL mutex callbacks!
  41. */
  42. #define URL "http://localhost/4KB"
  43. /* number of threads to fire up in parallel */
  44. #define NUM_THREADS 67
  45. /* how many times each URL is transferred per thread */
  46. #define URL_ITERATIONS 11235
  47. static pthread_mutex_t connlock;
  48. static size_t write_db(void *ptr, size_t size, size_t nmemb, void *data)
  49. {
  50. /* not interested in the downloaded bytes, return the size */
  51. (void)ptr; /* unused */
  52. (void)data; /* unused */
  53. return (size_t)(size * nmemb);
  54. }
  55. static void lock_cb(CURL *handle, curl_lock_data data,
  56. curl_lock_access access, void *userptr)
  57. {
  58. (void)access; /* unused */
  59. (void)userptr; /* unused */
  60. (void)handle; /* unused */
  61. (void)data; /* unused */
  62. pthread_mutex_lock(&connlock);
  63. }
  64. static void unlock_cb(CURL *handle, curl_lock_data data,
  65. void *userptr)
  66. {
  67. (void)userptr; /* unused */
  68. (void)handle; /* unused */
  69. (void)data; /* unused */
  70. pthread_mutex_unlock(&connlock);
  71. }
  72. static void init_locks(void)
  73. {
  74. pthread_mutex_init(&connlock, NULL);
  75. }
  76. static void kill_locks(void)
  77. {
  78. pthread_mutex_destroy(&connlock);
  79. }
  80. struct initurl {
  81. const char *url;
  82. CURLSH *share;
  83. int threadno;
  84. };
  85. static void *run_thread(void *ptr)
  86. {
  87. struct initurl *u = (struct initurl *)ptr;
  88. int i;
  89. for(i = 0; i < URL_ITERATIONS; i++) {
  90. CURL *curl = curl_easy_init();
  91. curl_easy_setopt(curl, CURLOPT_URL, u->url);
  92. curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);
  93. curl_easy_setopt(curl, CURLOPT_SHARE, u->share);
  94. curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_db);
  95. curl_easy_perform(curl); /* ignores error */
  96. curl_easy_cleanup(curl);
  97. fprintf(stderr, "Thread %d transfer %d\n", u->threadno, i);
  98. }
  99. return NULL;
  100. }
  101. int main(void)
  102. {
  103. pthread_t tid[NUM_THREADS];
  104. int i;
  105. int error;
  106. CURLSH *share;
  107. struct initurl url[NUM_THREADS];
  108. /* Must initialize libcurl before any threads are started */
  109. curl_global_init(CURL_GLOBAL_ALL);
  110. share = curl_share_init();
  111. curl_share_setopt(share, CURLSHOPT_LOCKFUNC, lock_cb);
  112. curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, unlock_cb);
  113. curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
  114. init_locks();
  115. for(i = 0; i< NUM_THREADS; i++) {
  116. url[i].url = URL;
  117. url[i].share = share;
  118. url[i].threadno = i;
  119. error = pthread_create(&tid[i], NULL, run_thread, &url[i]);
  120. if(0 != error)
  121. fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error);
  122. else
  123. fprintf(stderr, "Thread %d, gets %s\n", i, URL);
  124. }
  125. /* now wait for all threads to terminate */
  126. for(i = 0; i< NUM_THREADS; i++) {
  127. error = pthread_join(tid[i], NULL);
  128. fprintf(stderr, "Thread %d terminated\n", i);
  129. }
  130. kill_locks();
  131. curl_share_cleanup(share);
  132. curl_global_cleanup();
  133. return 0;
  134. }