[英]C++ UNIX threading
我正在使用UNIX和C ++中的线程进行项目。 基本上有一个生产者线程和5个使用者线程。 生产者线程在随机时间将递增的数字添加到队列中,而消费者线程轮询q以尝试将其删除。 由于某种原因,我的q.size()一直为负值,我不知道为什么。
#include <queue>
#include <list>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
using namespace std;
#define NUM_CONSUMER_THREADS 5
#define NUM_PRODUCER_THREADS 1
#define BUFFER_SIZE 20
void *c_thread_function(void *arg);
void *p_thread_function(void *arg);
queue<int> q;
int produce(int cur)
{
int temp = cur + 1;
return temp;
}
void append(int num)
{
if ( q.size() < BUFFER_SIZE )
{
q.push(num);
}
}
int take()
{
int removed = q.front();
q.pop();
sleep(1);
return removed;
}
void consume(int num, int thread)
{
printf("%d consumed %d \n", thread, num);
}
int main()
{
int result;
pthread_t cthreads[NUM_CONSUMER_THREADS];
pthread_t pthreads[NUM_PRODUCER_THREADS];
void *thread_result;
// build an array of consumer threads
for(int num_of_cthreads = 0; num_of_cthreads < NUM_CONSUMER_THREADS; num_of_cthreads++)
{
result = pthread_create(&(cthreads[num_of_cthreads]), NULL, c_thread_function, (void *)num_of_cthreads);
if ( result != 0 )
{
perror( "Thread Creation Failed");
exit(EXIT_FAILURE);
}
//sleep(1);
}
// build an array of producer threads
for(int num_of_pthreads = 0; num_of_pthreads < NUM_PRODUCER_THREADS; num_of_pthreads++)
{
result = pthread_create(&(pthreads[num_of_pthreads]), NULL, p_thread_function, NULL);
if ( result != 0 )
{
perror( "Thread Creation Failed");
exit(EXIT_FAILURE);
}
//sleep(1);
}
printf("All threads created\n");
while ( true )
{
// do nothing
}
}
void *c_thread_function(void *arg)
{
int temp = (long)arg;
printf("Consumer thread %d created \n", temp);
while ( true )
{
while ( q.size() > 0 )
{
int w = take();
consume(w, temp);
printf(" q size is now %d \n", q.size());
}
}
}
void *p_thread_function(void *arg)
{
printf("Producer thread created \n");
int itemsAdded = 0;
int temp;
int sleepTime;
while ( true )
{
while ( q.size() < BUFFER_SIZE )
{
temp = produce(itemsAdded);
sleepTime = 1+(int)(9.0*rand()/(RAND_MAX+1.0));
sleep(sleepTime);
append(temp);
printf("Producer adds: %d \n", temp);
printf(" q size is now %d \n", q.size());
itemsAdded++;
}
}
}
输出:
生产者添加:1
q大小现在是-1
0消耗了1
q大小现在是-2
1消耗了1
q大小现在是-3
3已消耗1
q大小现在是-4
4已消耗0
q大小现在是-5
0消耗了0
您需要了解种族条件和相互排斥的概念。 您的std::queue
对象是共享资源 ,这意味着有多个线程正在该线程上运行-可能同时运行 。 这意味着您必须使用锁(称为互斥锁)来保护它,以便每次访问都同步。 否则,您将获得所谓的竞态条件 ,其中一个线程修改数据,而另一个线程也在访问/修改数据,从而导致程序状态不一致或损坏。
为了防止出现竞争状况,您需要在每次队列访问之前锁定pthread_mutex
对象。
首先,您需要创建一个互斥对象并对其进行初始化。
pthread_mutex mymutex;
pthread_mutex_init(&mymutex, 0);
然后,您的应用程序代码应如下所示:
pthread_mutex_lock(&mymutex);
// Do something with queue
pthread_mutex_unlock(&mymutex);
当一个线程获取锁时,其他任何线程都无法获取锁。 试图获取已经被另一个线程获取的锁的线程将只等到释放该锁。 这将同步对队列的访问,确保一次只有一个线程对其进行修改。
STL容器(例如queue
不是线程安全的。 您需要同步对队列对象的访问,例如,使用互斥锁。
几个问题:
您正在忙着等待。
学习使用条件变量。 因此,线程等待不使用资源。
int temp = (long)arg;
不上班。
无法保证何时安排线程运行。
指针arg指向一个很久以前可能已更改的变量。
无论消费者/生产者线程修改阙q
没有获得独占访问。
任何其他线程都可以修改大小测试和添加材料点之间的队列。 更糟糕的是,另一个线程可能会同时尝试修改que(并且我相对确定STL对于修改不是线程安全的)。
尝试这样的事情:
#include <iostream>
#include <vector>
#include <queue>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#define CONSUMER_COUNT 5
#define PRODUCER_COUNT 2
struct ThreadQueue
{
ThreadQueue()
: finished(false)
{
if (pthread_mutex_init(&mutex, NULL) != 0)
{ throw int(1);
}
if (pthread_cond_init(&cond, NULL) != 0)
{
// Technically we should wrap the mutext.
// So if the condition variable fails it is
// auto destroyed. This is left as an exercise.
throw int(1);
}
}
~ThreadQueue()
{
if (pthread_cond_destroy(&cond) != 0)
{ //throw int(1); // Do we really care?
}
if (pthread_mutex_destroy(&mutex) != 0)
{ //throw int(1);
}
}
std::queue<int> data;
pthread_mutex_t mutex;
pthread_cond_t cond;
bool finished;
};
extern "C" void* consumerThread(void* arg)
{
ThreadQueue& que = *static_cast<ThreadQueue*>(arg);
while(!que.finished)
{
// Get the lock before proceeding
pthread_mutex_lock(&que.mutex);
while(que.data.size() == 0)
{
// If there is no data in the que the sleep on the condition.
pthread_cond_wait(&que.cond, &que.mutex);
// We may have been released here because of a signal.
// That does not mean we got out before one of the other
// consumer threads already stoll the value from the queue.
// So we must be in a loop and re-check the size() of the
// que before we proceed. If the value was already stolen
// then we go back to sleep waiting on the condition variable.
if (que.finished)
break;
}
// We have a lock with data in the que
int value = que.data.front();
que.data.pop();
// Use the same lock to access std::cout
std::cout << "Consumer Got: " << value << "\n";
pthread_mutex_unlock(&que.mutex);
}
return NULL;
}
extern "C" void* producerThread(void* arg)
{
ThreadQueue& que = *static_cast<ThreadQueue*>(arg);
while(!que.finished)
{
// Get the lock before proceeding
pthread_mutex_lock(&que.mutex);
// Add a new value to the queue
int value = rand();
que.data.push(value);
// Ise the same lock to access std::cout
std::cout << "Producer Push: " << value << "\n";
// Signal a consumer to be released.
pthread_cond_signal(&que.cond);
// rand maintains internal state.
// calls to rand() should therefore be protected by a mutex.
// Again in this simple example we re-use the same mutex for protection
int sleepTime = rand() % 5;
// Now release the lock
pthread_mutex_unlock(&que.mutex);
sleep(sleepTime);
}
return NULL;
}
int main()
{
srand(time(NULL));
ThreadQueue queue;
pthread_t consumerThreads[CONSUMER_COUNT];
pthread_t producerThreads[PRODUCER_COUNT];
try
{
for(int loop=0 ;loop < CONSUMER_COUNT; ++loop)
{
if (pthread_create(&consumerThreads[loop], NULL, consumerThread, &queue) != 0)
{ throw int(2);
}
}
for(int loop=0 ;loop < PRODUCER_COUNT; ++loop)
{
if (pthread_create(&producerThreads[loop], NULL, producerThread, &queue) != 0)
{ throw int(3);
}
}
}
catch(...)
{
// Set the finished to true so all threads exit.
queue.finished = true;
// Some consumers may be waiting on the condition.
// So wake them up one signal per consumer should do it.
for(int loop = 0;loop < CONSUMER_COUNT; ++loop)
{ pthread_cond_signal(&queue.cond);
}
}
/* Wait for all threads to finish */
for(int loop=0; loop < CONSUMER_COUNT; ++loop)
{
pthread_join(consumerThreads[loop], NULL);
}
for(int loop=0; loop < PRODUCER_COUNT; ++loop)
{
pthread_join(producerThreads[loop], NULL);
}
};
霍普,我说对了:-)
我发现了问题...
任务的重点是显示没有信号量的线程是多么不可靠。 这是我需要修复的代码...
int take()
{
int removed = q.front();
sleep(1); // switched
q.pop(); // these two...
return removed;
}
我还从生产者线程中删除了睡眠计时器。 现在一切正常...
输出现在执行此操作:
---Producer adds: 1 ---
---Producer adds: 2 ---
---Producer adds: 3 ---
---Producer adds: 4 ---
---Producer adds: 5 ---
---Producer adds: 6 ---
---Producer adds: 7 ---
---Producer adds: 8 ---
---Producer adds: 9 ---
---Producer adds: 10 ---
---Producer adds: 11 ---
---Producer adds: 12 ---
---Producer adds: 13 ---
---Producer adds: 14 ---
---Producer adds: 15 ---
---Producer adds: 16 ---
---Producer adds: 17 ---
---Producer adds: 18 ---
---Producer adds: 19 ---
---Producer adds: 20 ---
Thread 3 consumed 1
Thread 1 consumed 1
Thread 2 consumed 1
Thread 4 consumed 1
Thread 0 consumed 1
---Producer adds: 21 ---
---Producer adds: 22 ---
---Producer adds: 23 ---
---Producer adds: 24 ---
---Producer adds: 25 ---
Thread 3 consumed 6
Thread 4 consumed 6
Thread 1 consumed 6
---Producer adds: 26 ---
---Producer adds: 27 ---
---Producer adds: 28 ---
---Producer adds: 29 ---
---Producer adds: 30 ---
Thread 0 consumed 6
Thread 2 consumed 6
Thread 3 consumed 11
Thread 4 consumed 11
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.