C ++ - 线程导致奇怪的输出

时间:2013-01-04 03:26:03

标签: c++ pthreads

我不明白为什么我的代码会给我疯狂的输出,有时会出现段错误(代码是由我编写的08218722,以防我的大学检查是否存在抄袭)。

代码在C++中的Linux Mint中编写,并使用

进行编译
g++ -o code.exe code.cpp -lpthread

然后使用./code.exe运行。

代码应该生成一个随机字符向量(仅使用字符a,b,c,d,e和f),最多1000000,然后循环并计算它拥有的每个字符的数量。在我添加线程之前(在非线程和线程之间测试运行时的一部分),这个工作正常。所以我创建了1000个线程,告诉它们将1000个字符添加到向量中。我在这里做错了什么?

更新 - 代码仍然输出一些疯狂的结果 - 现在它不显示字符,而是某种方框

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <vector>
#include <algorithm>
#include <pthread.h>
#include <ctime>

using namespace std;

//Variable Declarations
const int length = 1000000; // length
const int packets = 1000; // packets length
const char chars[6] = {'a', 'b', 'c', 'd', 'e', 'f'}; // chars to choose
vector<char> charList(length); //vector of random charecter list
int charGroup[6] = {}; //stores char count
pthread_t threads[packets];



//Structure Declarations
struct dataStruct {
    int start;
    int end;
};

//Function Declarations
void *randomLetterGenerator(void * args); // Declaring function

// prints the vector
void outVector(char n)
{
    cout << n;
}

void GroupVector(char n)
{
   charGroup[n] = charGroup[n] + 1;
}

int main(){
        cout << "Creating a Random Char Array" << endl;
        cout << "using only letters ranging between a and f." << endl;
        //srand(time(NULL)); // sets the time seed
        clock_t start = clock();
        for(int i=0;i<length/packets;i++) {
            printf("\rPlease wait...%3d/%3d",i*packets,length);
            //Created in packets
            dataStruct ds;
            ds.start = i * (length/packets);
            ds.end = ds.start + (length/packets);
            pthread_create(&threads[i], NULL, randomLetterGenerator, (void *)&ds);
        }

        for(int i=0;i<length/packets;i++) {
            pthread_join(threads[i], NULL);
        }

        printf("\n"); //new line

        //prints out the new char list

        for_each(charList.begin(), charList.end(), outVector) ;

        printf("\n"); //new line

        //Counts and places in the correct array
        for_each(charList.begin(), charList.end(), GroupVector) ;

        int total = 0;

        for (int i = 0; i < 6; i++) {
            total += charGroup[chars[i]];
            cout << chars[i] << " = " << charGroup[chars[i]] << endl;
        }
        cout << "\nTotal: " << total << endl;
        clock_t ends = clock();
        cout << "Run Time :"
        << (double) (ends - start) / CLOCKS_PER_SEC << endl;
         pthread_exit(NULL);    
        return 0;   

}

void * randomLetterGenerator(void * datastruct){
    dataStruct ds = *((dataStruct *) datastruct);
    int start = ds.start;
    int end = ds.end;

     srand( time(NULL) );
    for(unsigned int c=start;c<end;c++){
        int i = (int) (rand() % 6);
        char rchar = chars[i];
        //--pthread_mutex_lock (&mutex);
        charList.at(c)= i;
        //--charList.push_back(rchar);  
        //--pthread_mutex_unlock (&mutex);  
    }
    pthread_exit(NULL);

}

2 个答案:

答案 0 :(得分:3)

很可能是因为你没有锁定。多个线程无法同时写入像vector这样的标准容器。当你的charList.push_back(rchar);函数中有许多线程正在执行randomLetterGenerator时,这正是你正在做的事情。您需要使用mutex包围此代码,例如:

pthread_mutex_t mutex;

void * randomLetterGenerator(void * datastruct)
{ 
    //Code as before
    //...
    //Lock the mutex
    charList.push_back(rchar);
    //Unlock the mutex
}

答案 1 :(得分:3)

你在这里使用了错误的方法。您需要创建一个适当大小的矢量,然后使用元素赋值将元素填充到其中。

使用向量的push_back函数将无法运行,并且可能会崩溃您的程序,因为它必须修改向量的内部状态,这不是线程安全的。如果你通过互斥锁将它包围起来它可以正常工作,但是你会完全抛弃窗外并行性的任何好处。

因此,创建一个具有所需条目数(vector<char> lots_of_chars(length);)的向量,然后使用项目分配来分配每个项目。每个线程都必须从向量的不同偏移处开始,这样它们就不会相互踩踏。

我会给你使用特定的代码来完成这项工作,但这听起来像是一项任务,所以我想我会让你为自己解决这个问题。

还有一个线程安全问题。它实际上可能不会导致任何问题,但你应该知道它。 rand不是线程安全的。它依赖于共享全局状态来生成连续的“随机”数字。除非你使用boost或C ++ 11,否则我所知道的线程安全随机数生成并不是一个好的选择。如果你有C ++ 11,你应该使用C ++ 11s构建线程支持而不是pthreads。

在这种特殊情况下,随机数生成实际生成随机数并不是非常重要。因此,如果线程通过随机数生成器相互踩踏并使其重复状态并生成相同的随机数序列或其他任何序列,则应该没问题。当然,这只是最有可能的结果。以这种非线程安全的方式使用rand实际上是未定义的行为,因此可能会发生任何事情。